Antworten:
Explaining_EXPLAIN.pdf könnte ebenfalls helfen.
Der Teil, den ich immer verwirrend fand, sind die Startkosten im Vergleich zu den Gesamtkosten. Ich google dies jedes Mal, wenn ich es vergesse, was mich hierher zurückbringt, was den Unterschied nicht erklärt, weshalb ich diese Antwort schreibe. Dies habe ich aus der Postgres- EXPLAIN
Dokumentation entnommen , die so erklärt wurde, wie ich sie verstehe.
Hier ist ein Beispiel aus einer Anwendung, die ein Forum verwaltet:
EXPLAIN SELECT * FROM post LIMIT 50;
Limit (cost=0.00..3.39 rows=50 width=422)
-> Seq Scan on post (cost=0.00..15629.12 rows=230412 width=422)
Hier ist die grafische Erklärung von PgAdmin:
(Wenn Sie PgAdmin verwenden, können Sie mit der Maus auf eine Komponente zeigen, um die Kostendetails zu lesen.)
Die Kosten werden als Tupel dargestellt wird , zum Beispiel die Kosten der LIMIT
ist cost=0.00..3.39
und die Kosten des sequenziellen Abtastung post
ist cost=0.00..15629.12
. Die erste Zahl im Tupel sind die Startkosten und die zweite Zahl sind die Gesamtkosten . Da ich verwendet habe EXPLAIN
und nicht EXPLAIN ANALYZE
, sind diese Kosten Schätzungen, keine tatsächlichen Maßnahmen.
Als Komplikation umfassen die Kosten jedes "übergeordneten" Knotens die Kosten seiner untergeordneten Knoten. In der Textdarstellung wird der Baum durch Einrückung dargestellt, z. B. LIMIT
ist er ein übergeordneter Knoten und Seq Scan
sein untergeordnetes Element . In der PgAdmin-Darstellung zeigen die Pfeile von Kind zu Elternteil - die Richtung des Datenflusses -, was möglicherweise nicht intuitiv ist, wenn Sie mit der Graphentheorie vertraut sind.
In der Dokumentation heißt es, dass die Kosten alle untergeordneten Knoten einschließen. Beachten Sie jedoch, dass die Gesamtkosten des übergeordneten 3.39
Knotens viel geringer sind als die Gesamtkosten des untergeordneten Knotens 15629.12
. Die Gesamtkosten sind nicht inklusive, da eine Komponente wie LIMIT
diese nicht ihre gesamte Eingabe verarbeiten muss. Siehe das EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 100 AND unique2 > 9000 LIMIT 2;
Beispiel in der Postgres- EXPLAIN
Dokumentation .
Im obigen Beispiel ist die Startzeit für beide Komponenten Null, da keine Komponente eine Verarbeitung durchführen muss, bevor sie mit dem Schreiben von Zeilen beginnt: Ein sequentieller Scan liest die erste Zeile der Tabelle und gibt sie aus. Der LIMIT
liest seine erste Zeile und gibt sie dann aus.
Wann müsste eine Komponente viel verarbeiten, bevor sie Zeilen ausgeben kann? Es gibt viele mögliche Gründe, aber schauen wir uns ein klares Beispiel an. Hier ist dieselbe Abfrage wie zuvor, die jetzt eine ORDER BY
Klausel enthält:
EXPLAIN SELECT * FROM post ORDER BY body LIMIT 50;
Limit (cost=23283.24..23283.37 rows=50 width=422)
-> Sort (cost=23283.24..23859.27 rows=230412 width=422)
Sort Key: body
-> Seq Scan on post (cost=0.00..15629.12 rows=230412 width=422)
Und grafisch:
Auch hier hat der sequentielle Scan post
keine Startkosten: Er beginnt sofort mit der Ausgabe von Zeilen. Die Sortierung hat jedoch erhebliche Startkosten, 23283.24
da die gesamte Tabelle sortiert werden muss, bevor auch nur eine einzelne Zeile ausgegeben werden kann . Die Gesamtkosten der Sortierung 23859.27
sind nur geringfügig höher als die Startkosten. Dies spiegelt die Tatsache wider, dass die sortierten Daten nach dem Sortieren des gesamten Datensatzes sehr schnell ausgegeben werden können.
Beachten Sie, dass die Startzeit von LIMIT
23283.24
genau der Startzeit der Sortierung entspricht. Dies liegt nicht daran, dass LIMIT
selbst eine hohe Startzeit vorliegt. Es hat für sich genommen keine Startzeit von Null, fasst jedoch EXPLAIN
alle untergeordneten Kosten für jeden Elternteil zusammen, sodass die LIMIT
Startzeit die Summe der Startzeiten seiner untergeordneten Elemente enthält.
Dieser Kostenaufschlag kann es schwierig machen, die Ausführungskosten jeder einzelnen Komponente zu verstehen. Zum Beispiel hat unsere LIMIT
keine Startzeit, aber das ist auf den ersten Blick nicht offensichtlich. Aus diesem Grund haben mehrere andere Personen auf EXPLAIN.depesz.com verlinkt , ein von Hubert Lubaczewski (auch bekannt als depesz) entwickeltes Tool, das das Verständnis erleichtert, EXPLAIN
indem es unter anderem die Kinderkosten von den Elternkosten abzieht. In einem kurzen Blogbeitrag über sein Tool erwähnt er einige andere Komplexitäten .
Es wird von am meisten eingerückt bis am wenigsten eingerückt ausgeführt, und ich glaube vom unteren Ende des Plans bis zum oberen Rand. (Wenn es also zwei eingerückte Abschnitte gibt, wird der eine weiter unten auf der Seite zuerst ausgeführt. Wenn sie den anderen treffen, wird die Regel ausgeführt, die sie verbindet.)
Die Idee ist, dass bei jedem Schritt 1 oder 2 Datensätze eintreffen und von einer Regel verarbeitet werden. Wenn nur ein Datensatz vorhanden ist, wird diese Operation für diesen Datensatz ausgeführt. (Scannen Sie beispielsweise einen Index, um herauszufinden, welche Zeilen Sie möchten, filtern Sie ein Dataset oder sortieren Sie es.) Wenn zwei, sind die beiden Datasets die beiden Dinge, die weiter eingerückt sind, und sie werden durch die angezeigte Regel verbunden. Die Bedeutung der meisten Regeln kann relativ leicht erraten werden (insbesondere, wenn Sie zuvor eine Reihe von Erklärungsplänen gelesen haben). Sie können jedoch versuchen, einzelne Elemente zu überprüfen, indem Sie entweder in der Dokumentation nachsehen oder (einfacher), indem Sie einfach den Satz hineinwerfen Google zusammen mit ein paar Keywords wie EXPLAIN
.
Dies ist offensichtlich keine vollständige Erklärung, bietet jedoch genügend Kontext, sodass Sie normalerweise herausfinden können, was Sie wollen. Betrachten Sie diesen Plan beispielsweise aus einer tatsächlichen Datenbank:
explain analyze
select a.attributeid, a.attributevalue, b.productid
from orderitemattribute a, orderitem b
where a.orderid = b.orderid
and a.attributeid = 'display-album'
and b.productid = 'ModernBook';
------------------------------------------------------------------------------------------------------------------------------------------------------------
Merge Join (cost=125379.14..125775.12 rows=3311 width=29) (actual time=841.478..841.478 rows=0 loops=1)
Merge Cond: (a.orderid = b.orderid)
-> Sort (cost=109737.32..109881.89 rows=57828 width=23) (actual time=736.163..774.475 rows=16815 loops=1)
Sort Key: a.orderid
Sort Method: quicksort Memory: 1695kB
-> Bitmap Heap Scan on orderitemattribute a (cost=1286.88..105163.27 rows=57828 width=23) (actual time=41.536..612.731 rows=16815 loops=1)
Recheck Cond: ((attributeid)::text = 'display-album'::text)
-> Bitmap Index Scan on (cost=0.00..1272.43 rows=57828 width=0) (actual time=25.033..25.033 rows=16815 loops=1)
Index Cond: ((attributeid)::text = 'display-album'::text)
-> Sort (cost=15641.81..15678.73 rows=14769 width=14) (actual time=14.471..16.898 rows=1109 loops=1)
Sort Key: b.orderid
Sort Method: quicksort Memory: 76kB
-> Bitmap Heap Scan on orderitem b (cost=310.96..14619.03 rows=14769 width=14) (actual time=1.865..8.480 rows=1114 loops=1)
Recheck Cond: ((productid)::text = 'ModernBook'::text)
-> Bitmap Index Scan on id_orderitem_productid (cost=0.00..307.27 rows=14769 width=0) (actual time=1.431..1.431 rows=1114 loops=1)
Index Cond: ((productid)::text = 'ModernBook'::text)
Total runtime: 842.134 ms
(17 rows)
Lesen Sie es selbst und prüfen Sie, ob es sinnvoll ist.
Was ich gelesen habe, ist, dass die Datenbank zuerst den id_orderitem_productid
Index scannt , anhand dessen die gewünschten Zeilen gefunden werden orderitem
, dann das Dataset mithilfe eines Quicksorts sortiert wird (die verwendete Sortierung ändert sich, wenn die Daten nicht in den RAM passen) und diese dann beiseite legt.
Als Nächstes wird orditematt_attributeid_idx
nach den gewünschten Zeilen gesucht orderitemattribute
und das Dataset mithilfe eines Quicksorts sortiert.
Anschließend werden die beiden Datensätze verwendet und zusammengeführt. (Ein Merge-Join ist eine Art "Zipping" -Operation, bei der die beiden sortierten Datasets parallel durchlaufen werden und die verknüpfte Zeile ausgegeben wird, wenn sie übereinstimmen.)
Wie gesagt, Sie arbeiten den Plan von innen nach außen, von unten nach oben durch.
Es gibt auch ein Online- Hilfstool , Depesz , das hervorhebt, wo sich die teuren Teile der Analyseergebnisse befinden.
hat auch eines, hier sind die gleichen Ergebnisse , die mir klarer machen, wo das Problem liegt.
PgAdmin zeigt Ihnen eine grafische Darstellung des Erklärungsplans. Das Hin- und Herwechseln zwischen den beiden kann Ihnen wirklich helfen, die Bedeutung der Textdarstellung zu verstehen. Wenn Sie jedoch nur wissen möchten, was zu tun ist, können Sie möglicherweise immer die GUI verwenden.
Die offizielle Dokumentation von PostgreSQL bietet eine interessante und gründliche Erklärung zum Verständnis der Ergebnisse von EXPLAIN.