

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

# Aurora DSQL EXPLAIN 計劃中的批次巢狀迴圈聯結
<a name="batched-nested-loop-joins"></a>

當查詢將小型外部輸入聯結到 Aurora DSQL 可以從儲存有效率地掃描的內部輸入時，Aurora DSQL 可以選擇`Nested Loop (Batched Join)`計劃。此聯結類型可在探查內部之前將多個外部資料列分組在一起，以減少運算和儲存層之間的往返。

標準巢狀迴圈一次處理一個外部資料列，並再次為每個資料列執行內部掃描。批次巢狀迴圈聯結會收集一批外部資料列、建置整個批次的內部掃描工作，然後將傳回的內部資料列聯結回相符的外部資料列。

## 批次巢狀迴圈聯結的運作方式
<a name="batched-nested-loop-joins-how-it-works"></a>

1. Aurora DSQL 會從聯結的外部讀取一批資料列。

1. 如果內部端是 `Index Scan`或 ，並在外部端`Index Only Scan`使用`Index Cond`參數化 ，Aurora DSQL 會繫結每個外部資料列的條件，並將產生的索引掃描金鑰合併為一個批次內部掃描。其他聯結述詞不會驅動內部掃描。

1. `Index Scan` 或`Index Only Scan`沒有外部參數化`Index Cond`的行為類似於 `Full Scan`或 `Sequential Scan`。Aurora DSQL 沒有參數化索引掃描金鑰，可合併每個外部批次執行一次內部掃描，而非每個外部資料列執行一次內部掃描。

1. Aurora DSQL 會在資料列到達批次時從內部串流資料列。在加入之前，不會具體化批次的整個內部結果。

1. 當內部 `Index Scan`或 `Index Only Scan`具有外部參數化 時`Index Cond`，Aurora DSQL 會使用 `Recheck Cond` 將每個傳回的內部資料列比對回批次中適用的外部資料列。Aurora DSQL 接著會套用任何剩餘的聯結述詞。如果沒有外部參數化 `Index Cond`，Aurora DSQL 會直接套用聯結述詞，因為它會比對每個串流的內部資料列與外部批次。

1. 對於左側和反聯結，Aurora DSQL 會追蹤哪些外部資料列相符，並在批次的內部掃描完成後發出不相符的資料列。

當內部是具有參數化 的索引掃描時，這種方法最有用`Index Cond`，因為合併的掃描金鑰提供整個外部批次的目標儲存存取權。

## 當 Aurora DSQL 使用此聯結時
<a name="batched-nested-loop-joins-when-used"></a>

當聯結的內側是實體掃描節點時，Aurora DSQL 會考慮批次巢狀迴圈聯結，這表示 `Index Scan`、`Full Scan`、 `Index Only Scan`或 `Sequential Scan`，且批次處理的成本預期低於為每個外部資料列執行內部掃描的成本。實際上，最大效益通常來自較小的外部輸入和內部索引掃描，其外部具有`Index Cond`參數化。

如果另一個計劃形狀更便宜，例如雜湊聯結或合併聯結，Aurora DSQL 會改為選擇該計劃。若要在調校期間比較計劃形狀，您可以停用目前工作階段的批次巢狀迴圈聯結：

```
SET dsql.enable_batched_nestloop = off;
```

## 如何讀取批次巢狀迴路聯結輸出
<a name="batched-nested-loop-joins-reading-output"></a>

下列查詢使用來自 的範例`transaction`和`account`資料表[讀取 Aurora DSQL EXPLAIN 計劃](reading-dsql-explain-plans.md)：

```
EXPLAIN
SELECT t.account_id, a.balance
FROM transaction t
LEFT JOIN account a
  ON t.account_id = a.customer_id
 AND a.balance > CASE
                    WHEN t.description LIKE 'fee%' THEN 0
                    ELSE 100
                  END
WHERE t.transaction_date >= '2025-01-01'
  AND (a.status = 'active' OR a.customer_id IS NULL)
ORDER BY t.account_id;
```

EXPLAIN 計劃可以包含類似下列的輸出：

```
Sort
  Sort Key: t.account_id
  -> Nested Loop (Batched Join)
       Filter: (((status)::text = 'active'::text) OR (customer_id IS NULL))
       Join Type: Left
       Recheck Cond: (customer_id = t.account_id)
       Join Filter: (balance > CASE WHEN (t.description ~~ 'fee%'::text) THEN '0'::numeric ELSE '100'::numeric END)
       -> Full Scan (btree-table) on transaction t
            -> Storage Scan on transaction t
                 Filters: (transaction_date >= '2025-01-01 00:00:00'::timestamp without time zone)
                 -> B-Tree Scan on transaction t
       -> Index Only Scan using idx1 on account a
            Index Cond: (customer_id = t.account_id)
```

`Nested Loop (Batched Join)`  
顯示 Aurora DSQL 在探測聯結的內側之前，正在批次處理外部資料列。

`Index Cond`  
顯示用來探測目前批次內部的述詞。當內側是 `Index Scan`或 時`Index Only Scan`，此述詞通常會參考聯結外側的資料欄。

`Filter`  
顯示套用至聯結結果的條件。在此範例中， `WHERE (a.status = 'active' OR a.customer_id IS NULL)`條件會顯示在此處。在標準 SQL 左聯結語意下，無法將此條件推送至內部掃描，因為這樣做會變更查詢結果。Aurora DSQL 會在聯結節點上將其顯示為篩選條件。相反地， 上的 條件只會`t.transaction_date`參考外部資料表，因此會出現在外部實體掃描下方。

`Join Type`  
顯示批次聯結的聯結語意，例如 `Left`、 `Semi`或 `Anti`。

`Recheck Cond`  
只有在內部端是 `Index Scan`或在聯結的外部`Index Only Scan`具有至少一個`Index Cond`參數化的 或 時才會出現。對於每個傳回的內部資料列，Aurora DSQL 會針對批次中的每個外部資料列執行重新檢查，以判斷哪些外部資料列產生該探查，並應該與該內部資料列聯結。

`Join Filter`  
顯示 Aurora DSQL 在將內部資料列比對回批次中的候選外部資料列後評估的聯結述詞。這些述詞會影響哪些資料列對聯結，但它們不會像`Index Cond`這樣驅動儲存探查。

先前的排序節點  
當查詢需要排序輸出時，可能會出現 。批次巢狀迴圈聯結不會保留與標準巢狀迴圈相同的輸出順序保證，因此 Aurora DSQL 可以在傳回最終結果集之前新增明確的排序。