

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 讀取 Aurora DSQL EXPLAIN 計劃
<a name="reading-dsql-explain-plans"></a>

了解如何讀取 EXPLAIN 計劃是最佳化查詢效能的關鍵。在本節中，我們將逐步介紹 Aurora DSQL 查詢計畫的真實範例、顯示不同掃描類型的行為、說明套用篩選條件的位置，以及強調最佳化的機會。

## 這些範例中使用的範例資料表
<a name="explain-plan-sample-tables"></a>

以下範例參考兩個資料表： `transaction`和 `account`。

`transaction` 資料表沒有主索引鍵，這會導致 Aurora DSQL 在查詢資料表時執行完整資料表掃描。

`account` 資料表在 上有索引`customer_id`。此索引包含 `balance`和 `status`作為涵蓋欄，這允許直接從索引滿足某些查詢，而無需從基礎資料表讀取。不過，索引不包含 `created_at`，因此參考此欄的查詢需要額外的資料表存取。

```
CREATE TABLE transaction (
    account_id uuid,
    transaction_date timestamp,
    description text
);

CREATE TABLE account (
    customer_id uuid,
    balance numeric,
    status varchar,
    created_at timestamp
);

CREATE INDEX ASYNC idx1 ON account (customer_id) INCLUDE (balance, status);
```

## 完整掃描範例
<a name="full-scan-example"></a>

Aurora DSQL 具有序列掃描，其功能與 PostgreSQL 和完整掃描相同。兩者之間的唯一區別是完整掃描可以對儲存體使用額外的篩選。因此，幾乎一律會在連續掃描上方選取。由於相似性，我們只會涵蓋更有趣的完整掃描範例。

完整掃描主要用於沒有主索引鍵的資料表。由於 Aurora DSQL 主金鑰預設為完全涵蓋索引，因此在 PostgreSQL 會使用循序掃描的許多情況下，Aurora DSQL 很可能在主金鑰上使用僅限索引掃描。與大多數其他資料庫一樣，沒有索引的資料表會嚴重擴展。

```
EXPLAIN SELECT account_id FROM transaction WHERE transaction_date > '2025-01-01' AND description LIKE '%external%';
```

```
                                                   QUERY PLAN
----------------------------------------------------------------------------------------------------------------
 Full Scan (btree-table) on transaction  (cost=125100.05..177933.38 rows=33333 width=16)
   Filter: (description ~~ '%external%'::text)
   -> Storage Scan on transaction (cost=12510.05..17793.38 rows=66666 width=16)
        Projections: account_id, description
        Filters: (transaction_date > '2025-01-01 00:00:00'::timestamp without time zone)
        -> B-Tree Scan on transaction (cost=12510.05..17793.38 rows=100000 width=30)
```

該計劃顯示在不同階段套用的兩個篩選條件。`transaction_date > '2025-01-01'` 條件會套用至儲存層，減少傳回的資料量。條件稍後`description LIKE '%external%'`會在傳輸資料後，於查詢處理器中套用，使其效率降低。將更多選擇性篩選條件推送至儲存體或索引層通常會改善效能。

## 僅限索引掃描範例
<a name="index-only-scan-example"></a>

僅索引掃描是 Aurora DSQL 中最理想的掃描類型，因為它們導致到儲存層的往返次數最少，並且可以進行最多的篩選。但是，因為您看到僅限索引掃描並不表示您擁有最佳計劃。由於可能發生的所有不同層級的篩選，仍須注意可能發生篩選的不同位置。

```
EXPLAIN SELECT balance FROM account 
WHERE customer_id = '4b18a761-5870-4d7c-95ce-0a48eca3fceb' 
AND balance > 100 
AND status = 'pending';
```

```
                                  QUERY PLAN
-------------------------------------------------------------------------------
 Index Only Scan using idx1 on account  (cost=725.05..1025.08 rows=8 width=18)
   Index Cond: (customer_id = '4b18a761-5870-4d7c-95ce-0a48eca3fceb'::uuid)
   Filter: (balance > '100'::numeric)
   -> Storage Scan on idx1 (cost=12510.05..17793.38 rows=9 width=16)
        Projections: balance
        Filters: ((status)::text = 'pending'::text)
        -> B-Tree Scan on idx1 (cost=12510.05..17793.38 rows=10 width=30)
            Index Cond: (customer_id = '4b18a761-5870-4d7c-95ce-0a48eca3fceb'::uuid)
```

在此計劃中，會先在索引掃描期間評估索引條件 `customer_id = '4b18a761-5870-4d7c-95ce-0a48eca3fceb'`，這是最有效率的階段，因為它會限制從儲存體讀取的資料量。儲存篩選條件 `status = 'pending'`會在資料讀取後，但在傳送至運算層之前套用，以減少傳輸的資料量。最後，查詢處理器篩選條件 會在資料移動後最後`balance > 100`執行，使其效率最低。其中，索引條件可提供最大效能，因為它會直接控制掃描的資料量。

## 索引掃描範例
<a name="index-scan-example"></a>

索引掃描類似於僅限索引掃描，但它們需要呼叫 基底資料表的額外步驟。由於 Aurora DSQL 可以指定儲存篩選條件，因此可以在索引呼叫和查詢呼叫上執行此操作。

為了清楚這一點，Aurora DSQL 會將計劃顯示為兩個節點。如此一來，您可以清楚地看到從儲存體傳回的資料列中新增包含資料欄將有多少幫助。

```
EXPLAIN SELECT balance FROM account 
WHERE customer_id = '4b18a761-5870-4d7c-95ce-0a48eca3fceb'
AND balance > 100 
AND status = 'pending' 
AND created_at > '2025-01-01';
```

```
                                                QUERY PLAN
----------------------------------------------------------------------------------------------------------
 Index Scan using idx1 on account  (cost=728.18..1132.20 rows=3 width=18)
   Filter: (balance > '100'::numeric)
   Index Cond: (customer_id = '4b18a761-5870-4d7c-95ce-0a48eca3fceb'::uuid)
   -> Storage Scan on idx1 (cost=12510.05..17793.38 rows=8 width=16)
        Projections: balance
        Filters: ((status)::text = 'pending'::text)
        -> B-Tree Scan on account (cost=12510.05..17793.38 rows=10 width=30)
            Index Cond: (customer_id = '4b18a761-5870-4d7c-95ce-0a48eca3fceb'::uuid)
   -> Storage Lookup on account (cost=12510.05..17793.38 rows=4 width=16)
        Filters: (created_at > '2025-01-01 00:00:00'::timestamp without time zone)
        -> B-Tree Lookup on transaction (cost=12510.05..17793.38 rows=8 width=30)
```

 此計劃顯示篩選如何跨多個階段進行：
+  上的索引條件會及早`customer_id `篩選資料。
+ 上的儲存篩選條件會`status`進一步縮小結果，然後再傳送至運算。
+ 上的查詢處理器篩選條件`balance`稍後會在傳輸後套用。
+ 從基礎資料表擷取其他資料欄時`created_at`，會評估 上的查詢篩選條件。

新增經常使用的資料欄，因為`INCLUDE`欄位通常可以消除此查詢並改善效能。

## 最佳實務
<a name="best-practices"></a>
+ 將**篩選條件與索引資料欄對齊**，以提早推送篩選。
+ **使用 INCLUDE 資料欄**允許僅限索引掃描並避免查詢。
+ 調查效能問題時**驗證資料列預估**。Aurora DSQL 會根據資料變更率`ANALYZE`在背景執行，以自動管理統計資料。如果估計值看起來不準確，您可以`ANALYZE`手動執行 以立即重新整理統計資料。
+ **避免大型資料表上的未索引查詢**，以避免昂貴的完全掃描。