Verwenden von EXPLAIN und EXPLAIN ANALYZE in Athena - Amazon Athena

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

Verwenden von EXPLAIN und EXPLAIN ANALYZE in Athena

Die EXPLAIN Anweisung zeigt den logischen oder verteilten Ausführungsplan einer bestimmten SQL Anweisung oder validiert die SQL Anweisung. Sie können die Ergebnisse im Textformat oder in einem Datenformat für das Rendern in einem Diagramm ausgeben.

Anmerkung

Sie können grafische Darstellungen logischer und verteilter Pläne für Ihre Abfragen in der Athena-Konsole anzeigen, ohne die EXPLAIN-Dateisyntax zu verwenden. Weitere Informationen finden Sie unter Ausführungspläne für SQL Abfragen anzeigen.

Die EXPLAIN ANALYZE Anweisung zeigt sowohl den verteilten Ausführungsplan einer bestimmten SQL Anweisung als auch die Rechenkosten der einzelnen Operationen in einer SQL Abfrage. Sie können die Ergebnisse als Text oder als JSON Format ausgeben.

Überlegungen und Einschränkungen

Die EXPLAIN- und EXPLAIN ANALYZE-Anweisungen in Athena unterliegen den folgenden Einschränkungen.

  • Da EXPLAIN-Abfragen keine Daten scannen, berechnet Athena keine Gebühren. Da EXPLAIN-Abfragen jedoch AWS Glue aufrufen, um Tabellen-Metadaten abzurufen, können Gebühren von Glue anfallen, wenn die Anrufe das kostenlose Kontingent für Glue überschreiten.

  • Weil EXPLAIN ANALYZE-Abfragen ausgeführt werden, scannen sie Daten und Athena berechnet die gescannte Datenmenge.

  • Die in Lake Formation definierten Zeilen- oder Zellenfilterinformationen und die Abfragestatistikinformationen werden in der Ausgabe von EXPLAIN und EXPLAIN ANALYZE nicht angezeigt.

EXPLAINSyntax

EXPLAIN [ ( option [, ...]) ] statement

option kann eine der folgenden sein:

FORMAT { TEXT | GRAPHVIZ | JSON } TYPE { LOGICAL | DISTRIBUTED | VALIDATE | IO }

Wenn die Option FORMAT nicht angegeben ist, wird standardmäßig das TEXT-Format ausgegeben. Der IO Typ stellt Informationen zu den Tabellen und Schemas bereit, die die Abfrage liest. IOwird nur in Athena-Engine-Version 2 unterstützt und kann nur im JSON Format zurückgegeben werden.

EXPLAINANALYZESyntax

Zusätzlich zu der in enthaltenen Ausgabe enthält die EXPLAIN ANALYZE Ausgabe auch Laufzeitstatistiken für die angegebene AbfrageEXPLAIN, wie z. B. die CPU Verwendung, die Anzahl der eingegebenen Zeilen und die Anzahl der ausgegebenen Zeilen.

EXPLAIN ANALYZE [ ( option [, ...]) ] statement

option kann einer der folgenden Werte sein:

FORMAT { TEXT | JSON }

Wenn die Option FORMAT nicht angegeben ist, wird standardmäßig das TEXT-Format ausgegeben. Weil alle Abfragen für EXPLAIN ANALYZE DISTRIBUTED sind, ist die Option TYPE für EXPLAIN ANALYZE nicht verfügbar.

statement kann einer der folgenden sein:

SELECT CREATE TABLE AS SELECT INSERT UNLOAD

EXPLAINBeispiele

Die folgenden Beispiele für EXPLAIN entwickeln sich von den einfacheren zu den komplexeren Beispielen.

Das folgende Beispiel EXPLAIN zeigt den Ausführungsplan für eine SELECT-Abfrage für Elastic-Load-Balancing-Protokolle. Das Format ist standardmäßig die Textausgabe.

EXPLAIN SELECT request_timestamp, elb_name, request_ip FROM sampledb.elb_logs;

Ergebnisse

- Output[request_timestamp, elb_name, request_ip] => [[request_timestamp, elb_name, request_ip]] - RemoteExchange[GATHER] => [[request_timestamp, elb_name, request_ip]] - TableScan[awsdatacatalog:HiveTableHandle{schemaName=sampledb, tableName=elb_logs, analyzePartitionValues=Optional.empty}] => [[request_timestamp, elb_name, request_ip]] LAYOUT: sampledb.elb_logs request_ip := request_ip:string:2:REGULAR request_timestamp := request_timestamp:string:0:REGULAR elb_name := elb_name:string:1:REGULAR

Sie können mit der Athena-Konsole einen Abfrageplan grafisch darstellen. Geben Sie eine SELECT Anweisung wie die folgende in den Athena-Abfrageeditor ein, und wählen Sie EXPLAINdann.

SELECT c.c_custkey, o.o_orderkey, o.o_orderstatus FROM tpch100.customer c JOIN tpch100.orders o ON c.c_custkey = o.o_custkey

Die Explain-Seite des Athena-Abfrage-Editors wird geöffnet und zeigt Ihnen einen verteilten Plan und einen logischen Plan für die Abfrage. Das folgende Diagramm zeigt den logischen Plan für das Beispiel.

Diagramm des vom Athena-Abfrage-Editor gerenderten Abfrageplans.
Wichtig

Derzeit sind einige Partitionsfilter im verschachtelten Operator-Baumdiagramm möglicherweise nicht sichtbar, obwohl Athena sie auf Ihre Abfrage anwendet. Um die Wirkung solcher Filter zu überprüfen, führen Sie EXPLAIN oder EXPLAIN ANALYZE auf Ihre Anfrage aus und sehen Sie sich die Ergebnisse an.

Weitere Informationen zur Verwendung der Abfrageplan-Diagrammfeatures in der Athena-Konsole finden Sie unter Ausführungspläne für SQL Abfragen anzeigen.

Wenn Sie ein Filterprädikat für einen partitionierten Schlüssel verwenden, um eine partitionierte Tabelle abzufragen, wendet das Abfragemodul das Prädikat auf den partitionierten Schlüssel an, um die Menge der gelesenen Daten zu reduzieren.

Im folgenden Beispiel wird eine EXPLAIN-Abfrage verwendet, um die Partitionsbereinigung für eine SELECT-Abfrage in einer partitionierten Tabelle zu überprüfen. Zuerst erstellt eine CREATE TABLE-Anweisung die tpch100.orders_partitioned-Tabelle. Die Tabelle ist nach Spalte o_orderdate partitioniert.

CREATE TABLE `tpch100.orders_partitioned`( `o_orderkey` int, `o_custkey` int, `o_orderstatus` string, `o_totalprice` double, `o_orderpriority` string, `o_clerk` string, `o_shippriority` int, `o_comment` string) PARTITIONED BY ( `o_orderdate` string) ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe' STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat' LOCATION 's3://amzn-s3-demo-bucket/<your_directory_path>/'

Die tpch100.orders_partitioned-Tabelle hat mehrere Partitionen auf o_orderdate, wie der Befehl SHOW PARTITIONS zeigt.

SHOW PARTITIONS tpch100.orders_partitioned; o_orderdate=1994 o_orderdate=2015 o_orderdate=1998 o_orderdate=1995 o_orderdate=1993 o_orderdate=1997 o_orderdate=1992 o_orderdate=1996

Die folgende EXPLAIN-Abfrage überprüft die Partitionsbereinigung für die angegebene SELECT-Anweisung.

EXPLAIN SELECT o_orderkey, o_custkey, o_orderdate FROM tpch100.orders_partitioned WHERE o_orderdate = '1995'

Ergebnisse

Query Plan - Output[o_orderkey, o_custkey, o_orderdate] => [[o_orderkey, o_custkey, o_orderdate]] - RemoteExchange[GATHER] => [[o_orderkey, o_custkey, o_orderdate]] - TableScan[awsdatacatalog:HiveTableHandle{schemaName=tpch100, tableName=orders_partitioned, analyzePartitionValues=Optional.empty}] => [[o_orderkey, o_custkey, o_orderdate]] LAYOUT: tpch100.orders_partitioned o_orderdate := o_orderdate:string:-1:PARTITION_KEY :: [[1995]] o_custkey := o_custkey:int:1:REGULAR o_orderkey := o_orderkey:int:0:REGULAR

Der fett gedruckte Text im Ergebnis zeigt, dass das Prädikat o_orderdate = '1995' auf den PARTITION_KEY angewendet wurde.

Die folgende EXPLAIN-Abfrage überprüft die Join-Reihenfolge und den Join-Typ der SELECT-Anweisung. Verwenden Sie eine Abfrage wie diese, um die Speicherauslastung der Abfrage zu untersuchen, um die Wahrscheinlichkeit eines EXCEEDED_LOCAL_MEMORY_LIMIT-Fehlers zu verringern.

EXPLAIN (TYPE DISTRIBUTED) SELECT c.c_custkey, o.o_orderkey, o.o_orderstatus FROM tpch100.customer c JOIN tpch100.orders o ON c.c_custkey = o.o_custkey WHERE c.c_custkey = 123

Ergebnisse

Query Plan Fragment 0 [SINGLE] Output layout: [c_custkey, o_orderkey, o_orderstatus] Output partitioning: SINGLE [] Stage Execution Strategy: UNGROUPED_EXECUTION - Output[c_custkey, o_orderkey, o_orderstatus] => [[c_custkey, o_orderkey, o_orderstatus]] - RemoteSource[1] => [[c_custkey, o_orderstatus, o_orderkey]] Fragment 1 [SOURCE] Output layout: [c_custkey, o_orderstatus, o_orderkey] Output partitioning: SINGLE [] Stage Execution Strategy: UNGROUPED_EXECUTION - CrossJoin => [[c_custkey, o_orderstatus, o_orderkey]] Distribution: REPLICATED - ScanFilter[table = awsdatacatalog:HiveTableHandle{schemaName=tpch100, tableName=customer, analyzePartitionValues=Optional.empty}, grouped = false, filterPredicate = ("c_custkey" = 123)] => [[c_custkey]] LAYOUT: tpch100.customer c_custkey := c_custkey:int:0:REGULAR - LocalExchange[SINGLE] () => [[o_orderstatus, o_orderkey]] - RemoteSource[2] => [[o_orderstatus, o_orderkey]] Fragment 2 [SOURCE] Output layout: [o_orderstatus, o_orderkey] Output partitioning: BROADCAST [] Stage Execution Strategy: UNGROUPED_EXECUTION - ScanFilterProject[table = awsdatacatalog:HiveTableHandle{schemaName=tpch100, tableName=orders, analyzePartitionValues=Optional.empty}, grouped = false, filterPredicate = ("o_custkey" = 123)] => [[o_orderstatus, o_orderkey]] LAYOUT: tpch100.orders o_orderstatus := o_orderstatus:string:2:REGULAR o_custkey := o_custkey:int:1:REGULAR o_orderkey := o_orderkey:int:0:REGULAR

Die Beispielabfrage wurde für eine bessere Leistung zu einem Cross-Join optimiert. Die Ergebnisse zeigen, dass tpch100.orders als BROADCAST-Verteilungstyp verteilt wird. Dies impliziert, dass die tpch100.orders-Tabelle an alle Knoten verteilt wird, die den Join-Vorgang ausführen. Der BROADCAST-Verteilungstyp erfordert, dass alle gefilterten Ergebnisse der tpch100.orders-Tabelle in den Speicher jedes Knotens passen, der die Join-Operation ausführt.

Die tpch100.customer-Tabelle ist jedoch kleiner als tpch100.orders. Da tpch100.customer weniger Speicher benötigt, können Sie die Abfrage in BROADCAST tpch100.customer statt in tpch100.orders umschreiben. Dies verringert die Wahrscheinlichkeit, dass die Abfrage den EXCEEDED_LOCAL_MEMORY_LIMIT-Fehler erhält. Diese Strategie setzt folgende Punkte voraus:

  • Das tpch100.customer.c_custkey ist in der tpch100.customer-Tabelle eindeutig.

  • Es besteht eine one-to-many Zuordnungsbeziehung zwischen tpch100.customer undtpch100.orders.

Im folgenden Beispiel wird die neu geschriebene Abfrage dargestellt.

SELECT c.c_custkey, o.o_orderkey, o.o_orderstatus FROM tpch100.orders o JOIN tpch100.customer c -- the filtered results of tpch100.customer are distributed to all nodes. ON c.c_custkey = o.o_custkey WHERE c.c_custkey = 123

Sie können eine EXPLAIN-Abfrage verwenden, um die Wirksamkeit des Filterns von Prädikaten zu überprüfen. Sie können die Ergebnisse verwenden, um Prädikate zu entfernen, die keine Auswirkung haben, wie im folgenden Beispiel.

EXPLAIN SELECT c.c_name FROM tpch100.customer c WHERE c.c_custkey = CAST(RANDOM() * 1000 AS INT) AND c.c_custkey BETWEEN 1000 AND 2000 AND c.c_custkey = 1500

Ergebnisse

Query Plan - Output[c_name] => [[c_name]] - RemoteExchange[GATHER] => [[c_name]] - ScanFilterProject[table = awsdatacatalog:HiveTableHandle{schemaName=tpch100, tableName=customer, analyzePartitionValues=Optional.empty}, filterPredicate = (("c_custkey" = 1500) AND ("c_custkey" = CAST(("random"() * 1E3) AS int)))] => [[c_name]] LAYOUT: tpch100.customer c_custkey := c_custkey:int:0:REGULAR c_name := c_name:string:1:REGULAR

Das filterPredicate in den Ergebnissen zeigt, dass der Optimierer die ursprünglichen drei Prädikate zu zwei Prädikaten zusammengeführt und ihre Anwendungsreihenfolge geändert hat.

filterPredicate = (("c_custkey" = 1500) AND ("c_custkey" = CAST(("random"() * 1E3) AS int)))

Da die Ergebnisse zeigen, dass das Prädikat AND c.c_custkey BETWEEN 1000 AND 2000 keine Auswirkung hat, können Sie dieses Prädikat entfernen, ohne die Abfrageergebnisse zu ändern.

Informationen zu den in den Ergebnissen von EXPLAIN-Abfragen verwendeten Begriffen finden Sie unter Verstehen Sie die Ergebnisse der EXPLAIN Athena-Erklärung.

EXPLAINANALYZEBeispiele

In den nachstehenden Beispielen wird ein Beispiel für EXPLAIN ANALYZE-Abfragen und Ausgaben gezeigt.

Das folgende Beispiel EXPLAIN ANALYZE zeigt den Ausführungsplan und die Rechenkosten für eine SELECT Abfrage von Protokollen. CloudFront Das Format ist standardmäßig die Textausgabe.

EXPLAIN ANALYZE SELECT FROM cloudfront_logs LIMIT 10

Ergebnisse

Fragment 1 CPU: 24.60ms, Input: 10 rows (1.48kB); per task: std.dev.: 0.00, Output: 10 rows (1.48kB) Output layout: [date, time, location, bytes, requestip, method, host, uri, status, referrer,\ os, browser, browserversion] Limit[10] => [[date, time, location, bytes, requestip, method, host, uri, status, referrer, os,\ browser, browserversion]] CPU: 1.00ms (0.03%), Output: 10 rows (1.48kB) Input avg.: 10.00 rows, Input std.dev.: 0.00% LocalExchange[SINGLE] () => [[date, time, location, bytes, requestip, method, host, uri, status, referrer, os,\ browser, browserversion]] CPU: 0.00ns (0.00%), Output: 10 rows (1.48kB) Input avg.: 0.63 rows, Input std.dev.: 387.30% RemoteSource[2] => [[date, time, location, bytes, requestip, method, host, uri, status, referrer, os,\ browser, browserversion]] CPU: 1.00ms (0.03%), Output: 10 rows (1.48kB) Input avg.: 0.63 rows, Input std.dev.: 387.30% Fragment 2 CPU: 3.83s, Input: 998 rows (147.21kB); per task: std.dev.: 0.00, Output: 20 rows (2.95kB) Output layout: [date, time, location, bytes, requestip, method, host, uri, status, referrer, os,\ browser, browserversion] LimitPartial[10] => [[date, time, location, bytes, requestip, method, host, uri, status, referrer, os,\ browser, browserversion]] CPU: 5.00ms (0.13%), Output: 20 rows (2.95kB) Input avg.: 166.33 rows, Input std.dev.: 141.42% TableScan[awsdatacatalog:HiveTableHandle{schemaName=default, tableName=cloudfront_logs,\ analyzePartitionValues=Optional.empty}, grouped = false] => [[date, time, location, bytes, requestip, method, host, uri, st CPU: 3.82s (99.82%), Output: 998 rows (147.21kB) Input avg.: 166.33 rows, Input std.dev.: 141.42% LAYOUT: default.cloudfront_logs date := date:date:0:REGULAR referrer := referrer:string:9:REGULAR os := os:string:10:REGULAR method := method:string:5:REGULAR bytes := bytes:int:3:REGULAR browser := browser:string:11:REGULAR host := host:string:6:REGULAR requestip := requestip:string:4:REGULAR location := location:string:2:REGULAR time := time:string:1:REGULAR uri := uri:string:7:REGULAR browserversion := browserversion:string:12:REGULAR status := status:int:8:REGULAR

Das folgende Beispiel zeigt den Ausführungsplan und die Rechenkosten für eine SELECT Abfrage von CloudFront Protokollen. Im Beispiel wird JSON das Ausgabeformat angegeben.

EXPLAIN ANALYZE (FORMAT JSON) SELECT * FROM cloudfront_logs LIMIT 10

Ergebnisse

{ "fragments": [{ "id": "1", "stageStats": { "totalCpuTime": "3.31ms", "inputRows": "10 rows", "inputDataSize": "1514B", "stdDevInputRows": "0.00", "outputRows": "10 rows", "outputDataSize": "1514B" }, "outputLayout": "date, time, location, bytes, requestip, method, host,\ uri, status, referrer, os, browser, browserversion", "logicalPlan": { "1": [{ "name": "Limit", "identifier": "[10]", "outputs": ["date", "time", "location", "bytes", "requestip", "method", "host",\ "uri", "status", "referrer", "os", "browser", "browserversion"], "details": "", "distributedNodeStats": { "nodeCpuTime": "0.00ns", "nodeOutputRows": 10, "nodeOutputDataSize": "1514B", "operatorInputRowsStats": [{ "nodeInputRows": 10.0, "nodeInputRowsStdDev": 0.0 }] }, "children": [{ "name": "LocalExchange", "identifier": "[SINGLE] ()", "outputs": ["date", "time", "location", "bytes", "requestip", "method", "host",\ "uri", "status", "referrer", "os", "browser", "browserversion"], "details": "", "distributedNodeStats": { "nodeCpuTime": "0.00ns", "nodeOutputRows": 10, "nodeOutputDataSize": "1514B", "operatorInputRowsStats": [{ "nodeInputRows": 0.625, "nodeInputRowsStdDev": 387.2983346207417 }] }, "children": [{ "name": "RemoteSource", "identifier": "[2]", "outputs": ["date", "time", "location", "bytes", "requestip", "method", "host",\ "uri", "status", "referrer", "os", "browser", "browserversion"], "details": "", "distributedNodeStats": { "nodeCpuTime": "0.00ns", "nodeOutputRows": 10, "nodeOutputDataSize": "1514B", "operatorInputRowsStats": [{ "nodeInputRows": 0.625, "nodeInputRowsStdDev": 387.2983346207417 }] }, "children": [] }] }] }] } }, { "id": "2", "stageStats": { "totalCpuTime": "1.62s", "inputRows": "500 rows", "inputDataSize": "75564B", "stdDevInputRows": "0.00", "outputRows": "10 rows", "outputDataSize": "1514B" }, "outputLayout": "date, time, location, bytes, requestip, method, host, uri, status,\ referrer, os, browser, browserversion", "logicalPlan": { "1": [{ "name": "LimitPartial", "identifier": "[10]", "outputs": ["date", "time", "location", "bytes", "requestip", "method", "host", "uri",\ "status", "referrer", "os", "browser", "browserversion"], "details": "", "distributedNodeStats": { "nodeCpuTime": "0.00ns", "nodeOutputRows": 10, "nodeOutputDataSize": "1514B", "operatorInputRowsStats": [{ "nodeInputRows": 83.33333333333333, "nodeInputRowsStdDev": 223.60679774997897 }] }, "children": [{ "name": "TableScan", "identifier": "[awsdatacatalog:HiveTableHandle{schemaName=default,\ tableName=cloudfront_logs, analyzePartitionValues=Optional.empty},\ grouped = false]", "outputs": ["date", "time", "location", "bytes", "requestip", "method", "host", "uri",\ "status", "referrer", "os", "browser", "browserversion"], "details": "LAYOUT: default.cloudfront_logs\ndate := date:date:0:REGULAR\nreferrer :=\ referrer: string:9:REGULAR\nos := os:string:10:REGULAR\nmethod := method:string:5:\ REGULAR\nbytes := bytes:int:3:REGULAR\nbrowser := browser:string:11:REGULAR\nhost :=\ host:string:6:REGULAR\nrequestip := requestip:string:4:REGULAR\nlocation :=\ location:string:2:REGULAR\ntime := time:string:1: REGULAR\nuri := uri:string:7:\ REGULAR\nbrowserversion := browserversion:string:12:REGULAR\nstatus :=\ status:int:8:REGULAR\n", "distributedNodeStats": { "nodeCpuTime": "1.62s", "nodeOutputRows": 500, "nodeOutputDataSize": "75564B", "operatorInputRowsStats": [{ "nodeInputRows": 83.33333333333333, "nodeInputRowsStdDev": 223.60679774997897 }] }, "children": [] }] }] } }] }

Weitere Ressourcen

Weitere Informationen finden Sie in den folgenden Ressourcen.

Visual query execution analysis in Amazon Athena (AWS YouTube channel)