

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.

# Ausführungsplan
<a name="aurora-analytics-execution-plan"></a>

Aurora PostgreSQL lässt sich in die EXPLAIN-Infrastruktur von PostgreSQL integrieren, um Ihnen zu helfen, zu verstehen, wie Abfragen ausgeführt werden, Pushdown-Möglichkeiten zu identifizieren und Leistungsprobleme zu diagnostizieren. In diesem Thema wird erklärt, wie Ausführungspläne für Abfragen in Fremdtabellen gelesen werden, welche Plantypen es gibt und welche Faktoren die Planauswahl beeinflussen.

**Topics**
+ [Plantypen](#aurora-analytics-plan-types)
+ [Einen Ausführungsplan lesen: Komplettlösung](#aurora-analytics-reading-plan-walkthrough)
+ [Verwenden Sie EXPLAIN VERBOSE, um Pushdown-SQL zu sehen](#aurora-analytics-explain-verbose)
+ [Grundlegendes zu „Nicht unterstützten Pushdown-Ausdrücken“](#aurora-analytics-unsupported-pushdown)
+ [Abfragen für den vollständigen Pushdown optimieren](#aurora-analytics-tuning-pushdown)
+ [EXPLAIN ANALYZE-Metrik-Referenz](#aurora-analytics-explain-analyze-metrics)
+ [Tipps für die Analyse des Ausführungsplans](#aurora-analytics-tips)

## Plantypen
<a name="aurora-analytics-plan-types"></a>

Aurora PostgreSQL verwendet zwei Pushdown-Strategien, die vom Planer automatisch ausgewählt werden:

**Topics**
+ [Vollständiger Abfrage-Pushdown](#aurora-analytics-full-pushdown)
+ [Table-scan Pushdown (Fallback)](#aurora-analytics-table-scan-pushdown)

### Vollständiger Abfrage-Pushdown
<a name="aurora-analytics-full-pushdown"></a>

Die gesamte Abfrage (einschließlich JOINs, Aggregationen, Unterabfragen, CTEs, ORDER BY und LIMIT) wird an die Analytics-Engine übertragen. Dies ist der schnellste Ausführungspfad.

Sie sehen einen einzelnen `Custom Scan` Knoten auf der obersten Ebene des Plans:

```
EXPLAIN (COSTS OFF) SELECT status, count(*), sum(total_amount)
FROM ft_orders
WHERE order_date > '2024-01-01'
GROUP BY status
ORDER BY sum(total_amount) DESC
LIMIT 5;
```

```
                 QUERY PLAN
--------------------------------------------
 Custom Scan
   ->  TOP_N
         Top: 5
         Order By: sum(total_amount) DESC
         ->  HASH_GROUP_BY
               Groups: #0
               Aggregates: count_star(), sum(#1)
               ->  READ_PARQUET
                     Table: ft_orders
                     Filters: order_date>'2024-01-01'
                     Projections: status, total_amount
```

Alles, was sich darin `Custom Scan` befindet, wird von der Analytics-Engine mithilfe einer spaltenbasierten Verarbeitung ausgeführt.

### Table-scan Pushdown (Fallback)
<a name="aurora-analytics-table-scan-pushdown"></a>

Wenn die vollständige Abfrage Konstrukte enthält, die nicht an die Analytical Engine übertragen werden können, greift Aurora PostgreSQL darauf zurück, nur den Fremdtabellenscan zu pushen. Beim Scan werden immer noch die unterstützten Filterbedingungen und Spaltenprojektionen heruntergesetzt, und die Engine liest nur die benötigten Spalten und Zeilen. Die JOINs-, Sortierungs- und nicht unterstützten Operationen werden dann in PostgreSQL ausgeführt.

Sie sehen `Custom Scan` Knoten, die in Standard-PostgreSQL-Knoten verschachtelt sind:

```
EXPLAIN (COSTS OFF) SELECT ft.price, soundex(ft.mainroad)
FROM ft_house_price ft
LIMIT 5;
```

```
              QUERY PLAN
--------------------------------------
 Limit
   ->  Custom Scan on ft_house_price
         ->  READ_PARQUET
               Table: ft_house_price
               Projections: price, mainroad
```

Hier `soundex()` ist eine PostgreSQL-Funktion, die nicht an die Analyse-Engine übertragen werden kann. Die Engine liest die Spalten (price, mainroad) effizient über READ\_PARQUET, dann wendet PostgreSQL lokal an. `soundex()`

## Einen Ausführungsplan lesen: Komplettlösung
<a name="aurora-analytics-reading-plan-walkthrough"></a>

In den folgenden Beispielen werden reale Ausführungspläne aus einem TPC-H SF100-Datensatz (\~34 GB Parquet) auf einer db.r8gd.8xlarge-Instance verwendet.

**Topics**
+ [Beispiel 1: Vollständiger Abfrage-Pushdown (Aggregation mit Filter)](#aurora-analytics-example-full-pushdown-aggregation)
+ [Beispiel 2: Multi-table JOIN mit vollständigem Pushdown](#aurora-analytics-example-multi-table-join)
+ [Beispiel 3: Vollständiger Abfrage-Pushdown mit einer lokalen Tabelle](#aurora-analytics-example-local-table)

### Beispiel 1: Vollständiger Abfrage-Pushdown (Aggregation mit Filter)
<a name="aurora-analytics-example-full-pushdown-aggregation"></a>

Dies ist TPC-H Abfrage 1, ein Scannen, Filtern, Gruppieren und Sortieren in einer einzigen großen Tabelle:

```
EXPLAIN (ANALYZE, VERBOSE, COSTS OFF, TIMING OFF, BUFFERS OFF, SUMMARY OFF)
SELECT l_returnflag, l_linestatus, count(*), sum(l_quantity), avg(l_extendedprice)
FROM ft_lineitem
WHERE l_shipdate <= '1998-09-01'
GROUP BY l_returnflag, l_linestatus
ORDER BY l_returnflag, l_linestatus;
```

```
 Custom Scan (actual rows=4 loops=1)
   Output: aurora_analytics.l_returnflag, aurora_analytics.l_linestatus, aurora_analytics.count, ...
   Pushdown SQL: SELECT l_returnflag, l_linestatus, count(*) AS count, sum(l_quantity) AS sum,
     avg(l_extendedprice) AS avg FROM (SELECT l_quantity::DECIMAL(15,2) AS l_quantity,
     l_extendedprice::DECIMAL(15,2) AS l_extendedprice, l_returnflag::VARCHAR COLLATE "C" AS l_returnflag,
     l_linestatus::VARCHAR COLLATE "C" AS l_linestatus, l_shipdate::DATE AS l_shipdate
     FROM system.main.read_parquet($aurora_analytics_parameter_1) AS ft_lineitem) ft_lineitem
     WHERE (l_shipdate <= '1998-09-01'::DATE)
     GROUP BY l_returnflag, l_linestatus ORDER BY l_returnflag, l_linestatus
   ->  ORDER_BY (actual rows=4 loops=1)
         Order By: ft_lineitem.l_returnflag ASC, ft_lineitem.l_linestatus ASC
         ->  HASH_GROUP_BY (actual rows=4 loops=1)
               Groups: #0, #1
               Aggregates: count_star(), sum(#2), avg(#3)
               ->  PROJECTION (actual rows=591411581 loops=1)
                     Projections: l_returnflag, l_linestatus, l_quantity, l_extendedprice
                     ->  READ_PARQUET (actual rows=591411581 loops=1)
                           Table: ft_lineitem
                           Filters: l_shipdate<='1998-09-01'::DATE
                           Projections: l_quantity, l_extendedprice, l_returnflag, l_linestatus
                           Total Files Read: 21
                           Rows Removed by Filter: 15303257125
 Analytics Cache Hit Bytes: 4617440kB
 Analytics Remote Read Bytes: 16kB
 S3 HEAD Request Count: 0
 S3 GET Request Count: 2
```

**Lesen Sie diesen Plan von unten nach oben:**

1. **READ\_PARQUET**: 21 `ft_lineitem` Parquet-Dateien durchsucht. Der Filter `l_shipdate <= '1998-09-01'` wurde auf die Scanebene verschoben (Prädikat Pushdown), wobei Zeilengruppen, die nicht übereinstimmten, übersprungen wurden. „Durch Filter entfernte Zeilen: 15.303.257.125“ bedeutet, dass Milliarden von Zeilengruppeneinträgen mithilfe von Statistiken entfernt wurden. min/max Es wurden nur 4 Spalten projiziert:,,,. `l_quantity` `l_extendedprice` `l_returnflag` `l_linestatus` Die anderen 12 Zeilenspalten wurden nie aus Amazon S3 gelesen.

1. **PROGNOSE**: 591 Millionen qualifizierte Zeilen mit den 4 projizierten Spalten wurden an die Aggregationsphase übergeben.

1. **HASH\_GROUP\_BY: Gruppiert** nach `l_returnflag` und `l_linestatus` (4 verschiedene Kombinationen), Berechnung, und. `count(*)` `sum(l_quantity)` `avg(l_extendedprice)` 591 Mio. Zeilen wurden auf 4 Ausgabezeilen reduziert.

1. **ORDER\_BY**: Die 4 Ergebniszeilen wurden nach, sortiert. `l_returnflag` `l_linestatus`

1. **Benutzerdefinierter Scan (aurora\_analytics**): Wrapper. Top-level Hat 4 Zeilen an PostgreSQL zurückgegeben. Die `Pushdown SQL` Zeile bestätigt, dass die gesamte Abfrage an die Analyse-Engine weitergeleitet wurde.

**Cache- und S3-Metriken:**
+ Cache-Treffer: \~4,5 GB (warm, Daten wurden aus früheren Läufen zwischengespeichert)
+ Fernlesen: 16 KB (fast alles wurde aus dem Cache bedient)
+ 0 HEAD-Anfragen, 2 GET-Anfragen (minimale Amazon S3 S3-Aktivität)
+ Fast alle Daten wurden mit minimaler Amazon S3 S3-Aktivität aus dem Cache bereitgestellt

### Beispiel 2: Multi-table JOIN mit vollständigem Pushdown
<a name="aurora-analytics-example-multi-table-join"></a>

Dies ist TPC-H Query 5, ein Join mit 4 Tabellen mit Filter, Aggregation, Sortierung und Limit:

```
EXPLAIN (ANALYZE, VERBOSE, COSTS OFF, TIMING OFF, BUFFERS OFF, SUMMARY OFF)
SELECT n_name, count(*), sum(l_extendedprice * (1 - l_discount)) as revenue
FROM ft_lineitem
JOIN ft_orders ON l_orderkey = o_orderkey
JOIN ft_customer ON o_custkey = c_custkey
JOIN ft_nation ON c_nationkey = n_nationkey
WHERE o_orderdate >= '1994-01-01' AND o_orderdate < '1995-01-01'
GROUP BY n_name
ORDER BY revenue DESC
LIMIT 5;
```

```
 Custom Scan (actual rows=5 loops=1)
   Output: aurora_analytics.n_name, aurora_analytics.count, (aurora_analytics.revenue)::numeric
   Pushdown SQL: SELECT ft_nation.n_name, count(*) AS count,
     sum((ft_lineitem.l_extendedprice * ((1::INTEGER)::numeric - ft_lineitem.l_discount))) AS revenue
     FROM ((((SELECT ... FROM system.main.read_parquet($aurora_analytics_parameter_1) AS ft_lineitem) ...
     JOIN ... ft_orders ... JOIN ... ft_customer ... JOIN ... ft_nation ...)))
     WHERE ((ft_orders.o_orderdate >= '1994-01-01'::DATE) AND (ft_orders.o_orderdate < '1995-01-01'::DATE))
     GROUP BY ft_nation.n_name
     ORDER BY ... DESC LIMIT 5::INTEGER
   ->  TOP_N (actual rows=5 loops=1)
         Top: 5
         Order By: sum(...) DESC
         ->  HASH_GROUP_BY (actual rows=25 loops=1)
               Groups: #0
               Aggregates: count_star(), sum(#1)
               ->  PROJECTION (actual rows=91044214 loops=1)
                     Projections: n_name, (l_extendedprice * (1.000 - CAST(l_discount AS DECIMAL(18,3))))
                     ->  HASH_JOIN (actual rows=91044214 loops=1)
                           Join Type: INNER
                           Conditions: l_orderkey = o_orderkey
                           ->  READ_PARQUET (actual rows=92006243 loops=1)
                                 Table: ft_lineitem
                                 Projections: l_orderkey, l_extendedprice, l_discount
                                 Dynamic Filters: optional: l_orderkey>=5 AND l_orderkey<=599999975
                                   AND l_orderkey IN BF(o_orderkey)
                                 Total Files Read: 21
                                 Rows Removed by Filter: 15802662463
                           ->  HASH_JOIN (actual rows=22760819 loops=1)
                                 Join Type: INNER
                                 Conditions: c_custkey = o_custkey
                                 ->  HASH_JOIN (actual rows=10099742 loops=1)
                                       Join Type: INNER
                                       Conditions: c_nationkey = n_nationkey
                                       ->  READ_PARQUET (actual rows=10099742 loops=1)
                                             Table: ft_customer
                                             Projections: c_custkey, c_nationkey
                                             Dynamic Filters: optional: c_custkey>=1 AND c_custkey<=14999999
                                               AND c_custkey IN BF(o_custkey)
                                             Total Files Read: 2
                                             Rows Removed by Filter: 856257246
                                       ->  READ_PARQUET (actual rows=25 loops=1)
                                             Table: ft_nation
                                             Projections: n_nationkey, n_name
                                             Total Files Read: 1
                                 ->  READ_PARQUET (actual rows=22760819 loops=1)
                                       Table: ft_orders
                                       Filters: o_orderdate>='1994-01-01'::DATE AND o_orderdate<'1995-01-01'::DATE
                                       Projections: o_orderkey, o_custkey
                                       Total Files Read: 6
                                       Rows Removed by Filter: 4526635795
 Analytics Cache Hit Bytes: 3330521kB
 Analytics Remote Read Bytes: 2514317kB
 S3 HEAD Request Count: 0
 S3 GET Request Count: 4922
```

**Lesen Sie diesen Plan von unten nach oben:**

1. **Vier READ\_PARQUET-Knoten**: Jede Fremdtabelle wird unabhängig gescannt:
   + `ft_nation`: 25 Zeilen aus einer Datei (Tabelle mit kleinen Dimensionen)
   + `ft_customer`: 10 Millionen Zeilen aus 2 Dateien, mit dynamischer Filterung beim Zusammenführen der Bestellungen
   + `ft_orders`: 22,8 Millionen Zeilen aus 6 Dateien, nach der Filterung bis zum Jahr 1994 (4,5 Milliarden Zeilen wurden durch den Datumsfilter entfernt)
   + `ft_lineitem`: 92 Millionen Zeilen aus 21 Dateien, wobei der Bloom-Filter über den Join-Key für Bestellungen gedrückt wird

1. **Drei HASH\_JOIN-Knoten**: Die Engine erstellt Hash-Tabellen und verknüpft sie der Reihe nach:
   + Nation Kunde (ein) `c_nationkey = n_nationkey`
   + Ergebnis Bestellungen (ein`o_custkey = c_custkey`)
   + Ergebnis Lineitem (ein) `l_orderkey = o_orderkey`

1. **Dynamische Filter**: Aurora PostgreSQL übergibt Join-Schlüsselbereiche und Bloom-Filter von der Build-Seite an den Scan der Testseite. Das `l_orderkey IN BF(o_orderkey)` bedeutet, dass nur Zeilenzeilen gelesen werden, die den Ordnungsschlüsseln entsprechen, was eine signifikante Optimierung darstellt.

1. **PROJEKTION**: Berechnet 91 Millionen `l_extendedprice * (1 - l_discount)` verbundene Zeilen.

1. **HASH\_GROUP\_BY: Gruppiert** nach `n_name` (25 Nationen), reduziert 91 Millionen Zeilen auf 25 Gruppen.

1. **TOP\_N**: Führt die Top 5 nach absteigendem Umsatz an.

**Cache- und S3-Metriken:**
+ Cache-Treffer: \~3,3 GB
+ Fernlesen: \~2,5 GB (teilweise Cache-Abdeckung, einige Daten sind noch kalt)
+ 4.922 S3 GET-Anfragen in 4 Tabellen (insgesamt 30 Dateien)
+ Der vollständige Abfrage-Pushdown wurde bestätigt: Alle 4 Tabellen wurden innerhalb der Analyse-Engine zusammengeführt

### Beispiel 3: Vollständiger Abfrage-Pushdown mit einer lokalen Tabelle
<a name="aurora-analytics-example-local-table"></a>

Eine hybride Abfrage, die eine Fremdtabelle mit einer lokalen PostgreSQL-Tabelle (Heap) verknüpft, kann vollständig nach unten verschoben werden: Die Analytics-Engine liest die lokale Tabelle und führt die Verknüpfung und Aggregation selbst durch, sofern die Abfrage nur unterstützte Funktionen, Datentypen und Sortierungen verwendet. Im folgenden Beispiel `local_supp` wird eine lokale Heap-Tabelle über Integer-Schlüssel mit der `ft_lineitem` Fremdtabelle verknüpft:

```
EXPLAIN (VERBOSE, COSTS OFF)
SELECT ls.s_regionkey, count(*)
FROM ft_lineitem
JOIN local_supp ls ON ft_lineitem.l_suppkey = ls.s_suppkey
WHERE l_shipdate > '1998-01-01'
GROUP BY ls.s_regionkey;
```

```
 Custom Scan
   Output: aurora_analytics.s_regionkey, aurora_analytics.count
   Pushdown SQL: SELECT ls.s_regionkey, count(*) AS count
     FROM ((SELECT l_suppkey::BIGINT AS l_suppkey, l_shipdate::DATE AS l_shipdate
            FROM system.main.read_parquet($aurora_analytics_parameter_1) AS ft_lineitem) ft_lineitem
       JOIN aurora_analytics.public.local_supp ls ON ((ft_lineitem.l_suppkey = ls.s_suppkey)))
     WHERE (ft_lineitem.l_shipdate > '1998-01-01'::DATE)
     GROUP BY ls.s_regionkey
   ->  HASH_GROUP_BY
         Groups: #0
         Aggregates: count_star()
         ->  PROJECTION
               Projections: s_regionkey
               ->  HASH_JOIN
                     Join Type: INNER
                     Conditions: l_suppkey = CAST(s_suppkey AS BIGINT)
                     ->  READ_PARQUET
                           Table: ft_lineitem
                           Filters: l_shipdate>'1998-01-01'::DATE
                           Projections: l_suppkey
                     ->  POSTGRES_SCAN
                           Table: local_supp
                           Projections: s_suppkey, s_regionkey
```

**Ich lese diesen Plan:**

1. **Einzelner benutzerdefinierter Scan auf oberster Ebene**: Die gesamte Abfrage, einschließlich der Verknüpfung mit der lokalen Tabelle, wird per Push an die Analytics-Engine übertragen. Im Gegensatz zum obigen Tablescan-Pushdown-Fall gibt es keine PostgreSQL-Knoten (HashAggregate, Hash Join), die es umschließen.

1. **POSTGRES\_SCAN (local\_supp)**: Die lokale Heap-Tabelle wird von der Analytics-Engine selbst gelesen und in die Push-Down-Tabelle eingespeist. `HASH_JOIN` Die lokale Tabelle nimmt an der Verknüpfung *innerhalb* der Engine teil, anstatt später von PostgreSQL verknüpft zu werden.

1. **READ\_PARQUET (ft\_lineitem)**: Beim Scannen fremder Tabellen werden nur der Filter und die Projekte übertragen. `l_shipdate` `l_suppkey`

1. **HASH\_JOIN, HASH\_GROUP\_BY: Der Join** und die /-Aggregation laufen beide innerhalb der Engine. `GROUP BY` `count(*)`

**Wichtiger Hinweis:** Das Verbinden einer fremden Tabelle mit einer lokalen Tabelle erzwingt keinen Fallback. Solange jede Funktion, jeder Datentyp und jede Sortierung in der Abfrage unterstützt werden, wird die lokale Tabelle in die Analytics-Engine übertragen und die gesamte Abfrage wird nach unten übertragen.

Das Verbinden einer fremden Tabelle mit einer lokalen PostgreSQL-Tabelle allein verhindert nicht den vollständigen Pushdown. Die Analyse-Engine kann eine lokale Tabelle in einen Push-Down-Join ziehen. Ein vollständiger Pushdown wird nur verhindert, wenn die Abfrage auf etwas verweist, das die Engine nicht herunterdrücken kann, z. B. eine Funktion, ein Datentyp oder eine Sortierung, die nicht unterstützt wird. Im folgenden Beispiel hat die Spalte n\_name der Tabelle Local Nation den Wert character (25), einen nicht unterstützten Typ, sodass Aurora PostgreSQL nur den Fremdtabellenscan pusht und den Join in PostgreSQL durchführt:

```
EXPLAIN (VERBOSE, COSTS OFF)
SELECT n_name, count(*)
FROM ft_lineitem
JOIN nation ON ft_lineitem.l_suppkey = nation.n_nationkey
WHERE l_shipdate > '1998-01-01'
GROUP BY n_name;
```

```
 HashAggregate
   Output: nation.n_name, count(*)
   Group Key: nation.n_name
   ->  Hash Join
         Output: nation.n_name
         Hash Cond: (l_suppkey = nation.n_nationkey)
         ->  Custom Scan on public.ft_lineitem
               Output: l_orderkey, l_partkey, l_suppkey, ...
               Pushdown SQL: SELECT l_suppkey FROM (SELECT l_suppkey::BIGINT AS l_suppkey,
                 l_shipdate::DATE AS l_shipdate
                 FROM system.main.read_parquet($aurora_analytics_parameter_1) AS ft_lineitem)
                 ft_lineitem WHERE (l_shipdate > '1998-01-01'::DATE)
               ->  READ_PARQUET
                     Table: ft_lineitem
                     Filters: l_shipdate>'1998-01-01'::DATE
                     Projections: l_suppkey
         ->  Hash
               Output: nation.n_name, nation.n_nationkey
               ->  Seq Scan on public.nation
                     Output: nation.n_name, nation.n_nationkey
 Unsupported Pushdown Expressions:
 1: Type
    Description: character(25)
```

**Ich lese diesen Plan:**

1. **Planstruktur**: Im Gegensatz zu den vorherigen Beispielen enthält dieser Plan PostgreSQL-Knoten (HashAggregate, Hash Join, Seq Scan), die den benutzerdefinierten Scan der Analyse-Engine einschließen. Dabei handelt es sich um einen Pushdown beim Tabellenscan, nicht um einen vollständigen Abfrage-Pushdown.

1. **Benutzerdefinierter Scan (ft\_lineitem)**: Aurora PostgreSQL verarbeitet nur den Fremdtabellenscan. Es überträgt nur `l_suppkey` den `l_shipdate > '1998-01-01'` Filter und projiziert, ein effizienter Spaltenscan mit Prädikats-Pushdown.

1. **Seq Scan (Nation)**: Die lokale `nation` Tabelle wird über den Standard-Executor von PostgreSQL gelesen (shared\_buffers → Aurora Storage).

1. **Hash Join**: PostgreSQL verbindet die beiden Ergebnismengen mithilfe eines Hash-Joins on. `l_suppkey = n_nationkey`

1. **HashAggregate**: PostgreSQL führt die Aggregation GROUP BY und count (\*) durch.

1. **Nicht unterstützte Pushdown-Ausdrücke**: Der Grund, warum der vollständige Pushdown fehlgeschlagen ist: `character(25)` (der `n_name` Spaltentyp in der lokalen Tabelle). `nation` Der `char(n)` Typ wird für Pushdown nicht unterstützt. Wenn es sich bei dieser Tabelle um eine Fremdtabelle mit `TEXT` Spalten handeln würde, wäre ein vollständiger Pushdown erfolgreich.

**Wichtiger Hinweis: Beim** Pushdown von Tabellenscans bietet Aurora PostgreSQL immer noch einen Mehrwert durch effizientes spaltenorientiertes Scannen mit Prädikat-Pushdown und Spaltenbereinigung. PostgreSQL verarbeitet nur die Operationen, die nicht nach unten verschoben werden können (nicht unterstützte Funktionen, Datentypen oder Sortierungen). Hätte die lokale Tabelle einen unterstützten Typ verwendet, z. B. `text` mit einer kompatiblen Sortierung, wäre der gesamte Hybrid-Join als einziger benutzerdefinierter Scan an die Analytics-Engine weitergeleitet worden.

## Verwenden Sie EXPLAIN VERBOSE, um Pushdown-SQL zu sehen
<a name="aurora-analytics-explain-verbose"></a>

`EXPLAIN VERBOSE`enthüllt das genaue SQL, das an die Analyse-Engine gesendet wurde:

```
EXPLAIN (VERBOSE, COSTS OFF)
SELECT status, count(*), avg(total_amount)
FROM ft_orders
WHERE order_date > '2024-01-01'
GROUP BY status;
```

```
                              QUERY PLAN
------------------------------------------------------------------------
 Custom Scan
   Output: aurora_analytics.status, aurora_analytics.count, aurora_analytics.avg
   Pushdown SQL: SELECT status, count(*) AS count, avg(total_amount) AS avg
     FROM (SELECT status::VARCHAR COLLATE "C" AS status,
                  total_amount::DECIMAL(12,2) AS total_amount,
                  order_date::TIMESTAMP AS order_date
           FROM system.main.read_parquet($aurora_analytics_parameter_1) AS ft_orders)
     ft_orders WHERE (order_date > '2024-01-01'::TIMESTAMP)
     GROUP BY status
   ->  HASH_GROUP_BY
         Groups: #0
         Aggregates: count_star(), avg(#1)
         ->  READ_PARQUET
               Table: ft_orders
               Filters: order_date>'2024-01-01'
               Projections: status, total_amount, order_date
```

Die `Pushdown SQL` Zeile zeigt:
+ Wie PostgreSQL-Typen in die Typen der Analytical Engine umgewandelt werden (zum Beispiel) `status::VARCHAR COLLATE "C"`
+ Die parametrisierte Dateireferenz () `$aurora_analytics_parameter_1`
+ Die exakten Werte WHERE, GROUP BY und Aggregationen werden an die Engine übertragen

## Grundlegendes zu „Nicht unterstützten Pushdown-Ausdrücken“
<a name="aurora-analytics-unsupported-pushdown"></a>

Wenn der vollständige Abfrage-Pushdown fehlschlägt, wird im `EXPLAIN VERBOSE` Abschnitt „Nicht unterstützte Pushdown-Ausdrücke“ angegeben, **warum**. Hier erfahren Sie, welche Konstrukte den Fallback zum Pushdown beim Tabellenscan erzwungen haben:

```
EXPLAIN (VERBOSE, COSTS OFF)
SELECT soundex(name), age
FROM ft_passengers
LIMIT 5;
```

```
                              QUERY PLAN
------------------------------------------------------------------------
 Limit
   Output: (soundex(name)), age
   ->  Custom Scan on public.ft_passengers
         Output: soundex(name), age
         Pushdown SQL: SELECT name, age
           FROM (SELECT name::VARCHAR COLLATE "C" AS name,
                        age::DOUBLE AS age
                 FROM system.main.read_parquet($aurora_analytics_parameter_1)
                 AS ft_passengers) ft_passengers
         ->  READ_PARQUET
               Table: ft_passengers
               Projections: name, age
 Unsupported Pushdown Expressions:
 1: Function
    Description: soundex(text)
```

Der Plan zeigt:
+ **PostgreSQL verarbeitet den Funktionsaufruf** `Limit` und `soundex()`
+ **Aurora PostgreSQL verarbeitet** nur den Tabellenscan (Lesen `name` und `age` Spalten)
+ **Grund**: `soundex(text)` ist keine Pushdown-sichere Funktion

**Topics**
+ [Kategorien von Ausdrücken, die nicht unterstützt werden](#aurora-analytics-unsupported-categories)

### Kategorien von Ausdrücken, die nicht unterstützt werden
<a name="aurora-analytics-unsupported-categories"></a>


| Kategorie | Beispiele | Problemlösung | 
| --- | --- | --- | 
| Funktion | soundex(text),st\_makepoint(...), uuid\_generate\_v4() UDFs | Schreiben Sie ohne die Funktion neu oder akzeptieren Sie den Tabellenscan-Pushdown | 
| Typ | vector, Besetzungen, bytea integer[] geometry | Verwenden Sie unterstützte Typen in Ausdrücken | 
| Operator | \~(Regex), LIKE mit Kollatierung außerhalb von C, (pgvector) <\+> | Verwenden Sie C-Kollation oder Pushdown-sichere Operatoren | 
| Kollation | Non-C Sortierung von Vergleichsausdrücken | Explizit verwenden COLLATE "C" | 
| Aggregate | percent\_rank(), array\_agg() | Schreiben Sie mit unterstützten Aggregaten um | 
| SQL-Syntax | ONLYSchlüsselwort, leere Zielliste, rekursive CTEs, dynamische Datenmaskierung | Strukturieren Sie die Abfrage neu | 

## Abfragen für den vollständigen Pushdown optimieren
<a name="aurora-analytics-tuning-pushdown"></a>

Um die Leistung zu maximieren, sollten Sie einen vollständigen Abfrage-Pushdown anstreben. Verwenden Sie diese `EXPLAIN VERBOSE` Option, um Ihre Abfragen zu überprüfen und nicht unterstützte Ausdrücke zu korrigieren:

**Schritt 1: Überprüfen Sie Ihre Abfrage**

```
EXPLAIN (VERBOSE, COSTS OFF) SELECT ... FROM ft_table ...;
```

Suchen Sie in der Ausgabe nach „Nicht unterstützte Pushdown-Ausdrücke“.

**Schritt 2: Identifizieren Sie die Ursache**

Falls vorhanden, lesen Sie die Kategorie und die Beschreibung, um zu verstehen, was den vollständigen Pushdown verhindert hat.

**Schritt 3: Korrigieren Sie den Ausdruck**
+ **Nicht unterstützte Funktion**: Es gibt kein Rewrite, das eine nicht unterstützte Funktion herunterdrückt. Wenn eine Abfrage eine nicht unterstützte Funktion (z. B.`soundex()`) auf eine fremde Tabellenspalte anwendet, greift Aurora PostgreSQL automatisch auf den Tabellenscan-Pushdown zurück: Es überträgt den Scan, die Projektion und alle unterstützten Filter weiterhin an die Analyse-Engine und wendet die Funktion in PostgreSQL auf die zurückgegebenen Zeilen an. Um den vollen Pushdown wiederherzustellen, vermeiden Sie die nicht unterstützte Funktion bei Abfragen von Fremdtabellen oder berechnen Sie das Ergebnis vorab in den Quelldaten. Andernfalls akzeptieren Sie den Pushdown für den Tabellenscan, wodurch Sie trotzdem effizient in Spalten scannen können.
+ **Non-C Sortierung: Fügen Sie explizite Textvergleiche** hinzu: `COLLATE "C"`

  ```
  -- Instead of:
  WHERE name LIKE 'Smith%'
  
  -- Use:
  WHERE name COLLATE "C" LIKE 'Smith%'
  ```
+ **Nicht unterstützter Typ**: Vermeiden Sie die Umwandlung in nicht unterstützte Typen in Ausdrücken für fremde Tabellenspalten.

**Schritt 4: Überprüfen**

Führen Sie nach dem Reparieren erneut aus `EXPLAIN VERBOSE` und stellen Sie sicher, dass „Unsupported Pushdown Expressions“ nicht mehr verfügbar ist.

## EXPLAIN ANALYZE-Metrik-Referenz
<a name="aurora-analytics-explain-analyze-metrics"></a>

Bei Verwendung `EXPLAIN ANALYZE` werden die folgenden analysespezifischen Metriken am Ende der `EXPLAIN` Ausgabe angezeigt, die Amazon S3- und Cache-Aktivitäten für die gesamte Abfrage zusammenfassen. Jedes hat eine entsprechende instanzweite CloudWatch Amazon-Metrik, die Sie für Dashboards und Alarme abfrageübergreifend verwenden können:


| Metrik | Description | Verwandte Metrik | 
| --- | --- | --- | 
| Analytics Cache Hit Bytes | Daten, die aus dem lokalen Festplatten-Cache bereitgestellt werden | AuroraAnalyticsCacheHit(Amazon CloudWatch, instanzweit) | 
| Analytics Remote Read Bytes | Von Amazon S3 abgerufene Daten (Cache-Fehler) | AuroraAnalyticsRemoteRead(Amazon CloudWatch, instanzweit) | 
| S3 HEAD Request Count | Anzahl der S3 HEAD-Anfragen (Metadatenprüfungen) | AuroraAnalyticsS3HeadRequest(Amazon CloudWatch, instanzweit) | 
| S3 GET Request Count | Anzahl der S3 GET-Anfragen (Datenabrufe) | AuroraAnalyticsS3GetRequest(Amazon CloudWatch, instanzweit) | 

Wenn `aurora_analytics.track_detailed_metrics` aktiviert, meldet jeder `Custom Scan` Knoten auch die folgenden Ausführungsmetriken pro Knoten:


| Metrik | Description | Verwandte Metrik | 
| --- | --- | --- | 
| Total CPU Time | CPU-Zeit, die die Analytics-Engine während der Ausführung dieses Knotens aufgewendet hat | siehe analytics\_total\_cpu\_time in aurora\_analytics\_stat\_statements() | 
| Effective Parallelism | Durchschnittliche Anzahl aktiver Worker-Threads während der Ausführung dieses Knotens | AuroraAnalyticsActiveThreads(Amazon CloudWatch, instanzweit) | 
| Total Thread Wait Time | Wartezeit der Worker-Threads der Engine während der Ausführung dieses Knotens | siehe analytics\_total\_thread\_wait\_time in aurora\_analytics\_stat\_statements() | 

## Tipps für die Analyse des Ausführungsplans
<a name="aurora-analytics-tips"></a>
+ Immer `EXPLAIN VERBOSE` beim Debuggen von Pushdown-Verhalten verwenden. Es zeigt sowohl als auch`Pushdown SQL`. `Unsupported Pushdown Expressions`
+ Ein einziger `Custom Scan` Eintrag auf der obersten Ebene des Plans = vollständiger Pushdown (am schnellsten). Ein `Custom Scan` verschachtelter innerer PostgreSQL-Knoten (egal ob einer oder mehrere) = Table-Scan-Pushdown (langsamer, nutzt aber immer noch den Spaltenscan).
+ Die folgende `Filters` Zeile `READ_PARQUET` bestätigt, dass Ihre WHERE-Klausel auf die Scanebene übertragen wurde. Wenn Sie stattdessen `Filter:` auf der `Custom Scan` Ebene sehen, wurde das Prädikat nicht ganz nach unten verschoben.
+ `Projections`unten `READ_PARQUET` zeigt, welche Spalten aus Parquet gelesen wurden. Eine Abfrage, die weniger Spalten projiziert, liest weniger Daten. Vermeiden `SELECT *` Sie fremde Tabellen.
+ `Total Files Read`gibt an, wie viele Parquet-Dateien gescannt wurden. Wenn dieser Wert hoch erscheint, sollten Sie eine Partitionierung Ihrer Daten in Betracht ziehen.
+ `Rows Removed by Filter`zeigt die Effektivität von Pushdown anhand von Prädikaten. Hohe Werte bedeuten, dass der Filter auf Scanebene einwandfrei funktioniert.