AlloyDB-Erklärungspläne abrufen und analysieren

Sie können Leistungsengpässe ermitteln und Ihre AlloyDB for PostgreSQL-Datenbankvorgänge optimieren, indem Sie Ausführungspläne abrufen und analysieren. Ein Ausführungsplan oder EXPLAIN-Plan ist eine detaillierte Darstellung der Art und Weise, wie Ihre AlloyDB-Datenbank-Engine eine SQL-Abfrage ausführen möchte. Der Ausführungsplan umfasst einen Baum von Knoten, in dem die Reihenfolge der Vorgänge wie Tabellenscans, Joins, Sortierungen und Aggregationen beschrieben wird, die die AlloyDB-Datenbank zum Abrufen der angeforderten Daten ausführt. Jeder Schritt in diesem Plan wird als Knoten bezeichnet.

Ein Ausführungsplan wird mit dem Befehl EXPLAIN abgerufen. Dieser gibt den Plan zurück, den der AlloyDB-Abfrageplaner für eine bestimmte SQL-Anweisung generiert. Ein Abfrageplaner, auch als Optimierungstool bezeichnet, ermittelt die effizienteste Methode zum Ausführen einer bestimmten SQL-Abfrage.

Ausführungspläne enthalten die folgenden Komponenten:

  • Planknoten: Sie stellen die verschiedenen Schritte bei der Ausführung der Abfrage dar, z. B. einen Scan, einen Join oder einen Sortiervorgang.
  • Ausführungszeit: Der EXPLAIN-Plan enthält die geschätzte oder tatsächliche Ausführungszeit für jeden Schritt. So lassen sich Datenbankengpässe ermitteln.
  • Pufferverwendung: Hier sehen Sie, wie viele Daten von der Festplatte im Vergleich zum Cache gelesen werden. So lassen sich Probleme beim Lesen von der Festplatte erkennen.
  • Parametereinstellungen: Im Plan werden die Parametereinstellungen angezeigt, die während der Ausführung der Abfrage gelten.

PostgreSQL und damit auch AlloyDB unterstützen Ausführungspläne für die folgenden Anweisungen:

  • SELECT
  • INSERT
  • UPDATE
  • DECLARE CURSOR
  • CREATE AS
  • CREATE MATERIALIZED VIEW
  • REFRESH MATERIALIZED VIEW
  • EXECUTE

Hinweise

Sie benötigen einen AlloyDB-Cluster und eine AlloyDB-Instanz. Weitere Informationen finden Sie unter Cluster und primäre Instanz erstellen.

Ausführungsplan erstellen

Sie generieren einen Ausführungsplan aus einer Clientanwendung wie psql, pgAdmin oder DBeaver. AlloyDB unterstützt das Generieren von Ausführungsplänen im Text- oder JSON-Format.

So generieren Sie einen Ausführungsplan:

  1. psql-Client mit einer Instanz verbinden
  2. Führen Sie den folgenden Befehl aus, um einen Ausführungsplan im Textformat zu generieren:

    SET enable_ultra_fast_cache_explain_output TO ON; /* AlloyDB Specific Command */
    EXPLAIN (analyze, verbose, columnar_engine, costs, settings, buffers, wal, timing, summary, format text)
    
  3. Führen Sie den folgenden Befehl aus, um einen Ausführungsplan im JSON-Format zu generieren:

    SET enable_ultra_fast_cache_explain_output TO ON; /* AlloyDB Specific Command */
    EXPLAIN (analyze, verbose, columnar_engine, costs, settings, buffers, wal, timing, summary, format json)
    

    Der Befehl EXPLAIN enthält alle verfügbaren Optionen – analyze, verbose, columnar_engine, costs, settings, buffers, wal, timing und summary –, um einen detaillierten Ausführungsplan für eine bestimmte Abfrage im Text- oder JSON-Format zu generieren. Die Option analyze bedeutet, dass die Abfrage ausgeführt wird, um sowohl tatsächliche Laufzeitstatistiken als auch die Schätzungen des Abfrageplaners zu liefern.

EXPLAIN-Plandaten ansehen und analysieren

Nachdem Sie einen Ausführungsplan erhalten haben, können Sie die Ergebnisse ansehen und analysieren.

Standardmäßig wird in der EXPLAIN-Ausgabe die serverseitige Abfrageaktivität angezeigt. Um die End-to-End-Roundtrip-Zeit zu messen, verwenden Sie die Option /timing in psql und speichern Sie die Ergebnisse in /dev/null.

Um den generierten Ausführungsplan zu sehen, verwenden Sie den Befehl EXPLAIN vor Ihrer SQL-Abfrage.

  • EXPLAIN SELECT...: Hier wird der Plan angezeigt, den der Optimierer ohne Ausführung der Abfrage auswählen würde.
  • EXPLAIN ANALYZE SELECT...: Führt die Abfrage aus und zeigt sowohl den vorhergesagten Plan als auch die tatsächlichen Ausführungsstatistiken an, einschließlich der tatsächlichen Laufzeiten und Zeilenanzahlen.

ERKLÄRE ohne ANALYSIERE

Wenn Sie die geschätzten Abfragekosten des Abfrageplaners sehen möchten, führen Sie eine EXPLAIN-Anweisung ohne die Option ANALYZE aus .

(postgres@10.3.1.17:5432) [postgres] > EXPLAIN select * from public.index_advisor_test;
                                   QUERY PLAN
---------------------------------------------------------------------------------
 Seq Scan on index_advisor_test  (cost=0.00..1735481.00 rows=100000000 width=27)
 AlloyDB query id: 7588555592527881263
 AlloyDB plan id: 16134093550604823483
(3 rows)

Die Planausgabe enthält die folgenden Daten:

  • cost = 0.00..1735481.00: Die erste Zahl gibt die Kosten für das Abrufen der ersten Zeile an. Die zweite Zahl gibt die Kosten für den Abruf der letzten Zeile an.
  • rows = 100000000: Dies ist die geschätzte Anzahl der Zeilen, die von der Abfrage zurückgegeben werden.
  • width = 27: Dies ist die geschätzte Breite der zurückgegebenen Zeile. Sie gibt Aufschluss über die aufgerufenen Blöcke.

Option „ANALYSIEREN“

Wenn Sie sowohl die tatsächlichen Ausführungsstatistiken als auch die geschätzten Ausführungsstatistiken sehen möchten, fügen Sie die Option ANALYZE hinzu.

(postgres@10.3.1.17:5432) [postgres] > EXPLAIN (ANALYZE) select * from public.index_advisor_test;
                                   QUERY PLAN
---------------------------------------------------------------------------------
 Seq Scan on index_advisor_test  (cost=0.00..1735481.00 rows=100000000 width=27) (actual time=0.165..9342.424 rows=100000001 loops=1)
 Planning Time: 0.025 ms
 Execution Time: 13674.794 ms
 AlloyDB query id: 7588555592527881263
 AlloyDB plan id: 16134093550604823483
(5 rows)

Die Planausgabe enthält die folgenden Daten:

  • actual time (in ms) = 0.165..9342.424: Hier sehen Sie die tatsächliche Zeit, die benötigt wurde, um die erste Zeile zurückzugeben, und die Gesamtzeit, die benötigt wurde, um alle Zeilen zurückzugeben.
  • rows = 100000001: Dies ist die tatsächliche Anzahl der zurückgegebenen Zeilen.
  • loops = 1: Dieser Wert ist wichtig für Knoten mit verschachtelten Schleifen. Wenn loops größer als 1 ist, wird die durchschnittliche Zeit pro Schleife angezeigt.
  • Planungszeit: 0,025 ms: Dies gibt die Zeit an, die der Planner benötigt hat, um den Ausführungspfad zu bestimmen.
  • Ausführungszeit: 13.674,794 ms: Dies gibt die Zeit an, die für die Ausführung benötigt wurde, nachdem der Planner den Pfad ermittelt hat.
  • Gesamtausführungszeit: die Summe aus Planning Time und Execution Time. (0,025 + 13.674,794 = 13.674,819)

Option „VERBOSE“

Mit der Option VERBOSE können Sie dem Ausführungsplan weitere Informationen hinzufügen. Im folgenden Beispiel werden mit VERBOSE Schemabeziehungen zu Tabellennamen hinzugefügt und eine interne Abfrage-ID angezeigt, mit der Sie Ihre Abfrage mit anderen Monitoring-Tools in Beziehung setzen können.

(postgres@10.3.1.17:5432) [postgres] > EXPLAIN (ANALYZE,VERBOSE) select * from public.index_advisor_test;
                                   QUERY PLAN
---------------------------------------------------------------------------------
Seq Scan on public.index_advisor_test  (cost=0.00..1735481.00 rows=100000000 width=27) (actual time=0.164..6568.938 rows=100000001 loops=1)
   Output: id, value, product_id, effective_date
 Query Identifier: -5175350694118300766
 Planning Time: 0.027 ms
 Execution Time: 10875.894 ms
 AlloyDB query id: 7588555592527881263
 AlloyDB plan id: 16134093550604823483

Die Planausgabe enthält die folgenden Daten:

  • Ausgabeknoten: Hier werden die in der Abfrage enthaltenen Spalten aufgeführt. Der Planer enthält manchmal mehr Spalten als angefordert, wenn es teurer wäre, sie wegzulassen.
  • Abfrage-ID: Die PostgreSQL-Kennung, die pg_stat_statements zugeordnet ist.
  • AlloyDB-Abfrage-ID: Die AlloyDB-Abfrage-ID, mit der Query Insights-Informationen korreliert werden können.

Option „COLUMNAR ENGINE“

Wenn Sie Informationen zur spaltenbasierten Engine von AlloyDB aufrufen möchten, fügen Sie die Option COLUMNAR_ENGINE hinzu.

Wenn die Tabelle nicht in der spaltenorientierten Engine vorhanden ist, sehen Sie sich den Status in der Spalte Columnar Check (Spaltenorientierte Prüfung) im folgenden Ausführungsplan an.

(postgres@10.3.1.17:5432) [postgres] > EXPLAIN (ANALYZE,VERBOSE, COLUMNAR_ENGINE) select * from public.index_advisor_test;
                                   QUERY PLAN
---------------------------------------------------------------------------------
Seq Scan on public.index_advisor_test  (cost=0.00..1735481.00 rows=100000000 width=27) (actual time=0.009..6328.154 rows=100000001 loops=1)
   Output: id, value, product_id, effective_date
   Columnar Check: table is not in the columnar store
 Query Identifier: -5175350694118300766
 Planning Time: 0.027 ms
 Execution Time: 10673.310 ms
 AlloyDB query id: 7588555592527881263
 AlloyDB plan id: 16134093550604823483

Wenn die Tabelle in der spaltenorientierten Engine vorhanden ist und die spaltenorientierte Engine verwendet wird, wird ein benutzerdefinierter Scan zusammen mit Statistiken zur Verwendung der spaltenorientierten Engine angezeigt.

(postgres@10.3.1.17:5432) [postgres] > EXPLAIN (ANALYZE,VERBOSE, COLUMNAR_ENGINE) select * from public.index_advisor_test where product_id = 1;
                                   QUERY PLAN
---------------------------------------------------------------------------------
Append  (cost=20.00..27438.78 rows=1166668 width=27) (actual time=0.066..377.029 rows=1000290 loops=1)
   ->  Custom Scan (columnar scan) on public.index_advisor_test  (cost=20.00..27437.66 rows=1166667 width=27) (actual time=0.065..296.904 rows=1000290 loops=1)
         Output: id, value, product_id, effective_date
         Filter: (index_advisor_test.product_id = 1)
         Rows Removed by Columnar Filter: 98999711
         Bytes fetched from storage cache: 774835915
         Columnar cache search mode: native
         Swap-in Time: 92.708 ms
   ->  Seq Scan on public.index_advisor_test  (cost=0.00..1.11 rows=1 width=27) (never executed)
         Output: id, value, product_id, effective_date
         Filter: (index_advisor_test.product_id = 1)
 Query Identifier: -4660018746142248761
 Planning Time: 0.217 ms
 Execution Time: 421.114 ms
 AlloyDB query id: 13855683355620344431
 AlloyDB plan id: 2126918133221480510

Die Planausgabe enthält die folgenden Daten:

  • Abfragefilter (Prädikat): Hier wird der angewendete Filter angezeigt, sofern Sie einen verwenden.
  • Durch Spaltenfilter entfernte Zeilen: Gibt die Anzahl der Zeilen an, die durch den Spaltenfilter entfernt wurden.
  • Aus Speichercache abgerufene Byte: Hier sehen Sie die Anzahl der Byte, die aus dem Speichercache abgerufen wurden.
  • Swap-in Time (Zeit für das Einlagern): Die Zeit, die erforderlich ist, um Daten aus dem spaltenweisen Spill-Cache (SSD) zu tauschen, wenn die Beziehung nicht in den Arbeitsspeicher passt.

Option „EINSTELLUNGEN“

Wenn Sie nicht standardmäßige Sitzungs-, Datenbank- oder globale Einstellungen sehen möchten, die vom Planner verwendet werden, fügen Sie die Option SETTINGS hinzu.

(postgres@10.3.1.17:5432) [postgres] > EXPLAIN (ANALYZE,VERBOSE, COLUMNAR_ENGINE,COSTS,SETTINGS) select * from public.index_advisor_test;

                                   QUERY PLAN
---------------------------------------------------------------------------------
Seq Scan on public.index_advisor_test  (cost=0.00..1735481.00 rows=100000000 width=27) (actual time=0.007..6366.249 rows=100000001 loops=1)
   Output: id, value, product_id, effective_date
   Columnar Check: table is not in the columnar store
 Settings: effective_cache_size = '19690120kB', random_page_cost = '1.1', work_mem = '256MB'
 Query Identifier: -5175350694118300766
 Planning Time: 0.027 ms
 Execution Time: 10727.068 ms
 AlloyDB query id: 7588555592527881263
 AlloyDB plan id: 16134093550604823483

Option „BUFFERS“

Verwenden Sie das Keyword BUFFERS, um Informationen zur Datenquelle aufzurufen. Die Anzahl der BUFFERS wird über alle Schritte hinweg kumuliert, nicht nur für einen bestimmten Schritt im Plan.

(postgres@10.3.1.17:5432) [postgres] > EXPLAIN (ANALYZE,VERBOSE, COLUMNAR_ENGINE,COSTS,SETTINGS, BUFFERS) select * from public.effective_io_concurrency_test;

                                   QUERY PLAN
---------------------------------------------------------------------------------
Seq Scan on public.effective_io_concurrency_test  (cost=0.00..1844356.96 rows=100058296 width=31) (actual time=0.111..10007.193 rows=100000001 loops=1)
   Output: id, value, product_id, effective_date
   Buffers: shared hit=1185 read=842625 dirtied=1, ultra fast cache hit=842625
   I/O Timings: shared read=2588.597
   Columnar Check: table is not in the columnar store
 Settings: effective_cache_size = '19690120kB', random_page_cost = '1.1', work_mem = '256MB'
 Query Identifier: -5987221491374921441
 Planning:
   Buffers: shared hit=58 read=2, ultra fast cache hit=2
   I/O Timings: shared read=0.215
 Planning Time: 0.410 ms
 Execution Time: 14825.271 ms
 AlloyDB query id: 12754549874439071326
 AlloyDB plan id: 13656575252012920931

Die Pufferinformationen umfassen Folgendes:

  • Gemeinsamer Treffer: Die Anzahl der 8-KB-Datenblöcke, die im Haupt-Cache für freigegebene Puffer von PostgreSQL gefunden wurden.
  • shared read (gemeinsames Lesen): Die Anzahl der 8-KB-Datenblöcke, die vom Betriebssystem gelesen wurden. Das weist oft auf Laufwerks-E/A hin.
  • dirtied: Die Anzahl der zuvor unveränderten Blöcke, die durch die Abfrage geändert wurden (Änderungen an der Sichtbarkeitskarte).
  • written: Die Anzahl der zuvor geänderten Blöcke, die von diesem Backend während der Abfrageverarbeitung aus dem Cache entfernt wurden, in der Regel aufgrund von Änderungen am Hinweisbit oder an der Sichtbarkeitsübersicht, und auf die Festplatte geschrieben wurden.
  • Treffer im ultraschnellen Cache: Anzahl der Blöcke, die aus dem ultraschnellen Cache abgerufen wurden.
  • E/A-Zeitangaben: Die Dauer von Festplatten- oder SSD-E/A-Vorgängen in Millisekunden.
  • Planung: Pufferaktivität während der Planungsphase, z. B. das Lesen von Metadaten oder Statistiken aus Katalogtabellen.
  • Für E/A während der Planung aufgewendete Zeit: Hier wird die E/A-Zeit angezeigt, wenn Metadaten vom Laufwerk gelesen werden mussten.

WAL-Option

Wenn Sie Informationen zu Write-Ahead Logging-Aktivitäten (WAL) bereitstellen möchten, verwenden Sie die Option WAL .

(postgres@10.3.1.17:5432) [postgres] > EXPLAIN (ANALYZE,VERBOSE, COLUMNAR_ENGINE,COSTS,SETTINGS, BUFFERS, WAL) select * from public.effective_io_concurrency_test;

                                   QUERY PLAN
---------------------------------------------------------------------------------
Seq Scan on public.effective_io_concurrency_test  (cost=0.00..1844356.96 rows=100058296 width=31) (actual time=0.010..10147.314 rows=100000001 loops=1)
   Output: id, value, product_id, effective_date
   Buffers: shared hit=1185 read=842625 dirtied=1, ultra fast cache hit=842625
   I/O Timings: shared read=2590.410
   WAL: records=18 bytes=5178
   Columnar Check: table is not in the columnar store
 Settings: effective_cache_size = '19690120kB', random_page_cost = '1.1', work_mem = '256MB'
 Query Identifier: -5987221491374921441
 Planning Time: 0.030 ms
 Execution Time: 15033.004 ms
 AlloyDB query id: 12754549874439071326
 AlloyDB plan id: 13656575252012920931

Die WAL-Informationen umfassen Folgendes:

  • WAL-Einträge: Die Anzahl der gelesenen WAL-Einträge, um die Konsistenz aufrechtzuerhalten.
  • WAL-Byte: Anzahl der Byte, die aus dem WAL gelesen wurden, um die Konsistenz aufrechtzuerhalten.
  • Einträge, die geändert, aber noch nicht checkpointed wurden: Dies weist auf Einträge hin, die geändert, aber noch nicht checkpointed wurden.

Nächste Schritte