

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

# 刪除動態分割區
<a name="pruning-dynamic-partitions"></a>

Spark 3.0 及更新版本包含動態分割區剔除 (DPP)。*動態分割區剔除*是 中的最佳化技術Spark，可防止讀取資料時掃描不必要的分割區。以下是一些有關 DPP 的重要須知：
+ 它會檢查查詢篩選條件和述詞中請求的分割區值，並判斷需要哪些分割區才能滿足查詢。任何被視為不必要的分割區都會自動且透明地剔除。
+ DPP 會略過不包含適用資料的分割區，以減少處理時間和資源使用率。這有助於僅Spark專注於相關分割區。
+ 它適用於透過插入或增量載入新增的靜態分割區和動態產生的分割區。 會Spark辨識新的分割區，並可繼續套用動態剔除。
+ DPP 完全透明或開發人員看不到。不需要特殊編碼即可啟用 DPP。在查詢計畫產生期間，會自動在幕後進行最佳化。

以下是確保 DPP 有效運作的一些最佳實務：
+ 在Spark資料框架操作的早期套用篩選條件，以使用述詞下推。這有助於透過使用分割區中繼資料提早Spark消除分割區。
+ `ANALYZE TABLE` 經常執行 ，以收集您資料的統計資料。這可減少資料欄層級統計資料，Spark有助於更準確地判斷可以忽略哪些分割區。
+ 避免過度分割您的資料。收集統計資料時，太多分割區可能會讓驅動程式節點超載。目標為每個大型資料表 10-100 個分割區。
+ 在聯結之前重新分割資料影格。這可防止需要移動所有資料的隨機聯結，並進一步最佳化讀取的資料量。
+ 在要聯結的不同資料表之間使用一致的分割區資料欄類型和命名。這有助於Spark更符合用於聯結最佳化的分割區。
+ 使用 測試查詢`EXPLAIN`，以確保 DPP 正在套用，並確認是否需要新增調校。

在*星星結構描述*中，資料表分為兩種主要類型：*事實*資料表和*維度*資料表。維度資料表通常比事實資料表小得多。將事實資料表加入維度資料表時，DPP 會最佳化查詢計畫。它會從套用至維度資料表的任何篩選條件建立子查詢。它會廣播此子查詢，並從中建置雜湊資料表。然後，它會先將雜湊資料表套用至事實資料表的掃描階段，再讀取事實資料表資料。這有助於 DPP 減少必須從較大事實資料表讀取的資料量。

下列範例查詢顯示動作中的 DPP。查詢會從國家 （印度） 擷取訂單數量，並在事實資料表 (`fact_orders`) 和維度資料表 () 之間包含內部聯結`nation`。`fact_orders` 資料表會依資料欄 分割`o_nationkey`。

```
- "select n.n_name as country, count(1) as no_of_orders from fact_orders o join nation n on o.o_nationkey = n.n_nationkey where n.n_name = 'INDIA' group by n.n_name"  
```

以下是`EXPLAIN`計劃中使用的步驟：

1. 掃描較小的維度資料表 (`nation`) 並依資料欄 篩選`n_name = 'INDIA'`。

1. 廣播上一個步驟的結果。

1. 建立篩選第一個步驟結果的子查詢。

1. 將其下推為 ，`PartitionFilter`使其僅掃描所需的事實資料表分割區，而不是完整資料表掃描。

以下是此 DPP 最佳化查詢的`EXPLAIN`計劃。

```
== Physical Plan ==
AdaptiveSparkPlan isFinalPlan=true
+- == Final Plan ==
   *(4) HashAggregate(keys=[], functions=[count(1)], output=[count#208L])
   +- ShuffleQueryStage 3
      +- Exchange SinglePartition, ENSURE_REQUIREMENTS, [id=#353]
         +- *(3) HashAggregate(keys=[], functions=[partial_count(1)], output=[count#212L])
            +- *(3) HashAggregate(keys=[n_name#31], functions=[], output=[])
               +- ShuffleQueryStage 1
                  +- Exchange hashpartitioning(n_name#31, 36), ENSURE_REQUIREMENTS, [id=#315]
                     +- *(2) HashAggregate(keys=[n_name#31], functions=[], output=[n_name#31])
                        +- *(2) Project [n_name#31]
                           +- *(2) BroadcastHashJoin [cast(o_nationkey#145 as bigint)], [n_nationkey#32L], Inner, BuildRight, false
                              :- *(2) ColumnarToRow
                              :  +- FileScan parquet [o_nationkey#145] Batched: true, DataFilters: [], Format: Parquet, Location: InMemoryFileIndex[s3://aws-spark-tuning/fact_orders], PartitionFilters: [isnotnull(o_nationkey#145), dynamicpruningexpression(cast(o_nationkey#145 as bigint) IN dynamicp..., PushedFilters: [], ReadSchema: struct<>
                              :        +- SubqueryBroadcast dynamicpruning#210, 0, [n_nationkey#32L], [id=#200]
                              :           +- OutputAdapter [n_name#31, n_nationkey#32L]
                              :              +- AdaptiveSparkPlan isFinalPlan=true
                              :                 +- BroadcastQueryStage 2
                              :                    +- ReusedExchange [n_name#31, n_nationkey#32L], BroadcastExchange HashedRelationBroadcastMode(List(input[1, bigint, false]),false), [id=#233]
                              +- BroadcastQueryStage 0
                                 +- BroadcastExchange HashedRelationBroadcastMode(List(input[1, bigint, false]),false), [id=#233]
                                    +- *(1) Filter ((isnotnull(n_name#31) AND (n_name#31 = INDIA)) AND isnotnull(n_nationkey#32L))
                                       +- FileScan json [n_name#31,n_nationkey#32L] Batched: false, DataFilters: [isnotnull(n_name#31), (n_name#31 = INDIA), isnotnull(n_nationkey#32L)], Format: JSON, Location: InMemoryFileIndex[s3://aws-spark-tuning/input/demo/json/nation], PartitionFilters: [], PushedFilters: [IsNotNull(n_name), EqualTo(n_name,INDIA), IsNotNull(n_nationkey)], ReadSchema: struct<n_name:string,n_nationkey:bigint>
```

即使資料`o_nationkey`欄上沒有新增直接篩選條件，由於 DPP 功能， Spark會自動僅掃描需要的分割區，而不是整個資料表。