Wovon EXPLAIN schweigt und wie man es zum Sprechen bringt

Eine klassische Frage, die Entwickler an ihren DBA oder GeschĂ€ftsinhaber – an einen PostgreSQL-Berater – stellen, lautet fast immer gleich: „Warum dauern die Abfragen auf der Datenbank so lange?“

Eine traditionelle Reihe von GrĂŒnden:

  • ineffizienter Algorithmus
    wenn Sie beschlossen haben, mehrere CTEs mit mehreren Zehntausend DatensĂ€tzen zu verknĂŒpfen
  • veraltete Statistiken.
    wenn die tatsĂ€chliche Verteilung der Daten in der Tabelle bereits stark von der zuletzt durchgefĂŒhrten ANALYSE abweicht
  • "Engpass" bei den Ressourcen
    und es an den zugewiesenen CPU-Ressourcen mangelt, Gigabytes an Speicher stĂ€ndig voll ausgelastet sind oder die Festplatte den vielen „WĂŒnschen“ der DB nicht gerecht wird
  • Sperrung wegen konkurrierender Prozesse

Und wenn Sperren schwer zu erfassen und zu analysieren sind, dann genĂŒgt uns fĂŒr alles andere der Abfrageplan, den man mit Hilfe von dem EXPLAIN-Befehl erhalten kann (am besten direkt EXPLAIN (ANALYZE, BUFFERS) ...) oder dem Modul auto_explain.

Aber, wie in der betreffenden Dokumentation erwÀhnt,

„Das VerstĂ€ndnis des Plans ist eine Kunst, und um diese zu meistern, benötigt man eine gewisse Erfahrung ...“

Aber man kann auch ohne diese auskommen, wenn man ein geeignetes Werkzeug verwendet!

Wie sieht ein Anfrageplan normalerweise aus? So etwa:

Index Scannen ĂŒber pg_class_relname_nsp_index auf pg_class (tatsĂ€chliche Zeit=0.049..0.050 Zeilen=1 Schleifen=1)
  Index Bedingung: (relname = $1)
  Filter: (oid = $0)
  Puffer: gemeinsamer Treffer=4
  InitPlan 1 (gibt $0,$1 zurĂŒck)
    ->  Limit (tatsÀchliche Zeit=0.019..0.020 Zeilen=1 Schleifen=1)
          Puffer: gemeinsamer Treffer=1
          ->  Seq Scannen auf pg_class pg_class_1 (tatsÀchliche Zeit=0.015..0.015 Zeilen=1 Schleifen=1)
                Filter: (relkind = 'r'::"char")
                Entfernte Zeilen durch Filter: 5
                Puffer: gemeinsamer Treffer=1

oder so:

"Append  (Kosten=868.60..878.95 Zeilen=2 Breite=233) (tatsÀchliche Zeit=0.024..0.144 Zeilen=2 Schleifen=1)"
"  Puffer: gemeinsamer Treffer=3"
"  CTE cl"
"    ->  Seq Scannen auf pg_class  (Kosten=0.00..868.60 Zeilen=9972 Breite=537) (tatsÀchliche Zeit=0.016..0.042 Zeilen=101 Schleifen=1)"
"          Puffer: gemeinsamer Treffer=3"
"  ->  Limit  (Kosten=0.00..0.10 Zeilen=1 Breite=233) (tatsÀchliche Zeit=0.023..0.024 Zeilen=1 Schleifen=1)"
"        Puffer: gemeinsamer Treffer=1"
"        ->  CTE Scannen auf cl  (Kosten=0.00..997.20 Zeilen=9972 Breite=233) (tatsÀchliche Zeit=0.021..0.021 Zeilen=1 Schleifen=1)"
"              Puffer: gemeinsamer Treffer=1"
"  ->  Limit  (Kosten=10.00..10.10 Zeilen=1 Breite=233) (tatsÀchliche Zeit=0.117..0.118 Zeilen=1 Schleifen=1)"
"        Puffer: gemeinsamer Treffer=2"
"        ->  CTE Scannen auf cl cl_1  (Kosten=0.00..997.20 Zeilen=9972 Breite=233) (tatsÀchliche Zeit=0.001..0.104 Zeilen=101 Schleifen=1)"
"              Puffer: gemeinsamer Treffer=2"
"Planungszeit: 0.634 ms"
"AusfĂŒhrungszeit: 0.248 ms"

Aber den Plan als Text »von der Liste« zu lesen, ist sehr schwierig und unĂŒbersichtlich:

  • im Knoten wird ausgegeben die Summe der Ressourcen des Teilbaums
    Das bedeutet, um zu verstehen, wie viel Zeit fĂŒr die AusfĂŒhrung eines bestimmten Knotens aufgewendet wurde oder wie genau dieses Lesen der Daten aus der Tabelle von der Festplatte abgerufen wurde – muss man irgendwie das Eine vom Anderen abziehen.
  • Die Knotenzeit ist erforderlich. Multiplizieren mit loops.
    Ja, Subtraktion ist noch nicht die komplizierteste Operation, die man „im Kopf“ durchfĂŒhren muss – schließlich wird die AusfĂŒhrungszeit als Durchschnitt fĂŒr einen einzelnen Knoten angegeben, und es können Hunderte von ihnen vorhanden sein.
  • Nun, all das zusammen erschwert die Antwort auf die Hauptfrage – also, wer ist das „schwĂ€chste Glied“??

Als wir versuchten, all dies mehreren Hundert unserer Entwickler zu erklĂ€ren, stellten wir fest, dass das von außen etwa so aussieht:

Wovon EXPLAIN schweigt und wie man es zum Sprechen bringt

Ah, das heißt, wir brauchen


Ein Tool

In diesem haben wir versucht, alle SchlĂŒsselmechaniken zu sammeln, die helfen, anhand des Plans und der Anfrage zu verstehen, „wer schuld ist und was zu tun ist“. Und außerdem wollten wir einen Teil unseres Wissens mit der Gemeinschaft teilen.
Treffen Sie und nutzen Sie – explain.tensor.ru

Anschaulichkeit der PlÀne

Ist es leicht, den Plan zu verstehen, wenn er so aussieht?

Seq Scan on pg_class (tatsÀchliche Zeit=0.009..1.304 Zeilen=6609 Schleifen=1)
  Buffer: shared hit=263
Planungszeit: 0,108 ms
AusfĂŒhrungszeit: 1,800 ms

Nicht wirklich.

Aber so, in verkĂŒrzter Form, wenn die SchlĂŒsselindikatoren getrennt sind – ist es bereits viel klarer:

Wovon EXPLAIN schweigt und wie man es zum Sprechen bringt

Aber wenn der Plan komplexer ist, kommt Hilfe von Kreisdiagramm der Zeitverteilung nach Knoten:

Wovon EXPLAIN schweigt und wie man es zum Sprechen bringt

FĂŒr die kompliziertesten Varianten steht uns auch die AusfĂŒhrungsdiagramm:

Wovon EXPLAIN schweigt und wie man es zum Sprechen bringt

Es gibt tatsÀchlich Nicht-Trivial-FÀlle, in denen ein Plan mehr als eine tatsÀchliche Wurzel haben kann:

Wovon EXPLAIN schweigt und wie man es zum Sprechen bringtWovon EXPLAIN schweigt und wie man es zum Sprechen bringt

Strukturelle Hinweise

Wenn die gesamte Struktur des Plans und dessen Schwachstellen bereits aufgegliedert und sichtbar sind, warum dann nicht dem Entwickler markieren und «in verstÀndlicher Sprache» erklÀren?

Wovon EXPLAIN schweigt und wie man es zum Sprechen bringtSolcher Empfehlungsvorlagen haben wir bereits einige Dutzend gesammelt.

Zeilenprofilierer der Anfrage

Wenn wir nun den analysierten Plan mit der ursprĂŒnglichen Anfrage kombinieren, können wir sehen, wie viel Zeit jeder einzelne Operator in Anspruch genommen hat — etwa so:

Wovon EXPLAIN schweigt und wie man es zum Sprechen bringt


 oder sogar so:

Wovon EXPLAIN schweigt und wie man es zum Sprechen bringt

Parameterersetzung in der Anfrage

Wenn Sie nicht nur die Anfrage, sondern auch deren Parameter aus der DETAIL-Zeile des Logs an den Plan angehÀngt haben, können Sie ihn in einer der Varianten zusÀtzlich kopieren:

  • mit den Werten in der Anfrage ersetzt
    zum unmittelbaren AusfĂŒhren auf Ihrer Datenbank und zur weiteren Profilierung
    SELECT 'const', 'param'::text;
  • mit den Werten ĂŒber PREPARE/EXECUTE ersetzt
    fĂŒr die Simulation der Arbeitsweise des Planers, wenn der parametrische Teil ignoriert werden kann – zum Beispiel bei der Arbeit mit partitionierten Tabellen
    DEALLOCATE ALL;
    PREPARE q(text) AS SELECT 'const', $1::text;
    EXECUTE q('param'::text);
    

Planarchive

FĂŒgen Sie hinzu, analysieren Sie, teilen Sie mit Kollegen! Die PlĂ€ne bleiben im Archiv, und Sie können spĂ€ter darauf zurĂŒckgreifen: explain.tensor.ru/archive

Wenn Sie jedoch nicht möchten, dass Ihr Plan von anderen gesehen wird, vergessen Sie nicht, das KÀstchen "nicht im Archiv veröffentlichen" anzukreuzen.

In den kommenden Artikeln werde ich ĂŒber die Herausforderungen und Lösungen sprechen, die bei der Analyse von PlĂ€nen auftreten.

Quelle: habr.com

Erwerben Sie zuverlĂ€ssiges Hosting fĂŒr Websites mit DDoS-Schutz, VPS VDS-Server đŸ”„ Kaufen Sie zuverlĂ€ssiges Hosting fĂŒr Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster