支援的版本:目前 (17) / 16 / 15 / 14 / 13
開發版本:devel
不支援的版本:12 / 11 / 10 / 9.6

15.3. 平行計畫 #

由於每個 worker 會完整執行計畫的平行部分,因此不可能簡單地採用一般的查詢計畫並使用多個 worker 執行它。每個 worker 都會產生輸出結果集的完整副本,因此查詢的執行速度不會比平常快,但會產生不正確的結果。相反地,計畫的平行部分必須是查詢最佳化器內部稱為部分計畫的東西;也就是說,必須以這樣的方式建構它,使得執行該計畫的每個程序只會產生輸出列的子集,並且以保證每個所需的輸出列都只會由其中一個合作程序產生。一般來說,這表示查詢的驅動表格上的掃描必須是支援平行的掃描。

15.3.1. 平行掃描 #

目前支援以下類型的支援平行的表格掃描。

  • 平行循序掃描中,表格的區塊將被分成範圍,並在合作程序之間共用。每個 worker 程序將在要求額外的區塊範圍之前,完成對其給定區塊範圍的掃描。

  • 平行位元圖堆積掃描中,會選擇一個程序作為領導者。該程序會掃描一個或多個索引,並建立一個位元圖,指示需要走訪哪些表格區塊。然後,這些區塊會像平行循序掃描一樣,在合作程序之間進行劃分。換句話說,堆積掃描是以平行方式執行的,但底層的索引掃描不是。

  • 平行索引掃描平行僅索引掃描中,合作程序輪流從索引讀取資料。目前,平行索引掃描僅支援 btree 索引。每個程序將宣告一個單一索引區塊,並將掃描並傳回該區塊引用的所有元組;其他程序可以同時從不同的索引區塊傳回元組。平行 btree 掃描的結果會以排序的順序在每個 worker 程序中傳回。

其他掃描類型(例如非 btree 索引的掃描)將來可能會支援平行掃描。

15.3.2. 平行聯結 #

就像在非平行計畫中一樣,驅動表格可以使用巢狀迴圈、雜湊聯結或合併聯結來聯結到一個或多個其他表格。聯結的內側可以是規劃器支援的任何種類的非平行計畫,前提是它可以在平行 worker 中安全地執行。根據聯結類型,內側也可能是一個平行計畫。

  • 巢狀迴圈聯結中,內側始終是非平行的。雖然它會完整執行,但如果內側是索引掃描,則這是有效率的,因為外部元組以及在索引中查尋值的迴圈會分散在合作程序中。

  • 合併聯結中,內側始終是非平行計畫,因此會完整執行。這可能效率不高,尤其是在必須執行排序的情況下,因為工作和產生的資料會在每個合作程序中重複。

  • 雜湊聯結(不帶 "parallel" 前綴)中,每個合作程序都會完整執行內側,以建立雜湊表的相同副本。如果雜湊表很大或計畫很昂貴,這可能效率不高。在平行雜湊聯結中,內側是一個平行雜湊,它會在合作程序之間劃分建構共用雜湊表的工作。

15.3.3. 平行聚合 #

PostgreSQL 支援透過兩個階段的聚合來進行平行聚合。首先,參與查詢的平行部分的每個程序都會執行聚合步驟,針對該程序知道的每個群組產生部分結果。這會在計畫中反映為 Partial Aggregate 節點。其次,部分結果透過 GatherGather Merge 傳輸到領導者。最後,領導者重新聚合所有 worker 的結果,以產生最終結果。這會在計畫中反映為 Finalize Aggregate 節點。

由於 Finalize Aggregate 節點在領導者程序上執行,因此相對於輸入列的數量而言,產生相對大量群組的查詢,對於查詢規劃器來說,似乎不太有利。例如,在最糟的情況下,Finalize Aggregate 節點看到的群組數量可能與所有 worker 程序在 Partial Aggregate 階段看到的輸入列數量一樣多。對於這種情況,顯然使用平行聚合不會帶來任何效能上的好處。查詢規劃器在規劃過程中會將此納入考量,並且不太可能在這種情況下選擇平行聚合。

並非在所有情況下都支援平行聚合。每個聚合必須是對於平行處理是安全的,並且必須具有組合函式。如果聚合具有 internal 類型的轉換狀態,則它必須具有序列化和反序列化函式。請參閱 CREATE AGGREGATE 以取得更多詳細資料。如果任何聚合函式呼叫包含 DISTINCTORDER BY 子句,則不支援平行聚合,而且也不支援排序集合聚合,或者當查詢涉及 GROUPING SETS 時。它只能在查詢中涉及的所有聯結也是計畫的平行部分的一部分時使用。

15.3.4. 平行附加 #

PostgreSQL 需要將來自多個來源的資料列合併為單一結果集時,它會使用 AppendMergeAppend 規劃節點。這通常發生在實作 UNION ALL 或掃描分割資料表時。這些節點可以像在任何其他規劃中一樣,在平行規劃中使用。然而,在平行規劃中,規劃器可能會改用 Parallel Append 節點。

Append 節點在平行規劃中使用時,每個程序將按照它們出現的順序執行子規劃,以便所有參與的程序協作執行第一個子規劃直到完成,然後大約在同一時間移動到第二個規劃。當改用 Parallel Append 時,執行器會盡可能均勻地將參與的程序分散到其子規劃中,以便同時執行多個子規劃。這避免了爭用,也避免了在那些從未執行的程序中支付子規劃的啟動成本。

此外,與常規的 Append 節點不同,常規的 Append 節點在平行規劃中使用時只能有部分子節點,而 Parallel Append 節點可以同時具有部分和非部分子規劃。非部分子節點將僅由單個程序掃描,因為多次掃描它們將產生重複的結果。因此,即使沒有有效的局部規劃可用,涉及附加多個結果集的規劃也能實現粗粒度的平行處理。例如,考慮對分割資料表進行查詢,該查詢只能通過使用不支持平行掃描的索引來有效地實現。規劃器可能會選擇常規 Index Scan 規劃的 Parallel Append;每個單獨的索引掃描都必須由單個程序執行到完成,但不同的掃描可以由不同的程序同時執行。

可以使用enable_parallel_append 來停用此功能。

15.3.5. 平行規劃提示 #

如果預期生成平行規劃的查詢沒有生成,您可以嘗試降低 parallel_setup_costparallel_tuple_cost。當然,這個規劃可能會比規劃器首選的序列規劃慢,但情況並非總是如此。如果您即使使用這些設定的非常小的值(例如,將它們都設定為零)也無法獲得平行規劃,則可能有一些原因導致查詢規劃器無法為您的查詢生成平行規劃。有關原因,請參閱第 15.2 節第 15.4 節

執行平行規劃時,您可以使用 EXPLAIN (ANALYZE, VERBOSE) 來顯示每個規劃節點的每個工作程序的統計資訊。這對於確定工作是否在所有規劃節點之間平均分配,以及更廣泛地了解規劃的效能特性可能很有用。

提交更正

如果您在文件中發現任何不正確、與您使用特定功能的經驗不符或需要進一步澄清的地方,請使用此表單來回報文件問題。