由於每個工作程序都會將計劃的並行部分執行完畢,因此無法簡單地採用一個普通的查詢計劃並用多個工作程序來執行。每個工作程序都會生成一份完整的輸出結果集,因此查詢不會比正常執行快,但會產生錯誤的結果。相反,計劃的並行部分必須是查詢最佳化器內部稱為 部分計劃 的東西;也就是說,它必須構造得使執行該計劃的每個程序只生成輸出行的子集,並且保證每一行所需的輸出都由一個協作程序生成。通常,這意味著查詢的驅動表上的掃描必須是支援並行的掃描。
目前支援以下型別的並行掃描表。
在 並行順序掃描 中,表的塊將被分成範圍並由協作程序共享。每個工作程序在請求另一塊範圍之前將完成其給定塊範圍的掃描。
在 並行點陣圖堆掃描 中,會選擇一個程序作為領導者。該程序執行一個或多個索引的掃描,並構建一個位圖,指示需要訪問哪些表塊。然後,這些塊將像在並行順序掃描中一樣在協作程序之間分配。換句話說,堆掃描是並行執行的,但底層的索引掃描不是。
在 並行索引掃描 或 並行僅索引掃描 中,協作程序輪流從索引讀取資料。目前,僅對 btree 索引支援並行索引掃描。每個程序將宣告一個單獨的索引塊,並掃描並返回該塊引用的所有元組;其他程序可以同時從不同的索引塊返回元組。並行 btree 掃描的結果在每個工作程序內以排序順序返回。
其他掃描型別,例如非 btree 索引的掃描,將來可能會支援並行掃描。
與非並行計劃一樣,驅動表可以使用巢狀迴圈、雜湊連線或合併連線連線到一個或多個其他表。連線的內側可以是規劃器支援的任何型別的非並行計劃,前提是可以在並行工作程序中安全執行。根據連線型別,內側也可以是並行計劃。
在 巢狀迴圈連線 中,內側始終是非並行的。儘管它會被完整執行,但如果內側是索引掃描,這是很高效的,因為外層元組以及因此查詢索引值的迴圈被分散到協作程序中。
在 合併連線 中,內側始終是非並行計劃,因此會完整執行。這可能效率低下,尤其是當必須執行排序時,因為工作和生成的資料會在每個協作程序中重複。
在 雜湊連線(不帶“並行”字首)中,內側由每個協作程序完整執行以構建相同的雜湊表副本。如果雜湊表很大或計劃很昂貴,這可能會效率低下。在 並行雜湊連線 中,內側是 並行雜湊,它將構建共享雜湊表的工作分配給協作程序。
PostgreSQL 透過分兩階段進行聚合來支援並行聚合。首先,參與查詢並行部分的每個程序執行一個聚合步驟,為該程序瞭解的每個組生成一個部分結果。這在計劃中體現為 Partial Aggregate
節點。其次,部分結果透過 Gather
或 Gather Merge
傳輸給領導者。最後,領導者跨所有工作程序重新聚合結果以生成最終結果。這在計劃中體現為 Finalize Aggregate
節點。
由於 Finalize Aggregate
節點在領導者程序上執行,因此與輸入行數相比,產生相對較多組的查詢對於查詢規劃器來說吸引力較小。例如,在最壞的情況下,Finalize Aggregate
節點看到的組數可能與所有工作程序在 Partial Aggregate
階段看到的輸入行數一樣多。對於這種情況,使用並行聚合顯然不會帶來效能上的好處。查詢規劃器在規劃過程中會考慮這一點,並且不太可能在這種情況下選擇並行聚合。
並行聚合並非在所有情況下都受支援。每個聚合都必須 對並行安全 並且必須有一個組合函式。如果聚合的過渡狀態型別為 internal
,則它必須具有序列化和反序列化函式。有關更多詳細資訊,請參閱 CREATE AGGREGATE。如果任何聚合函式呼叫包含 DISTINCT
或 ORDER BY
子句,並且也不支援有序集聚合或查詢涉及 GROUPING SETS
,則不支援並行聚合。只有當查詢中涉及的所有連線也是計劃的並行部分的一部分時,才能使用它。
每當 PostgreSQL 需要將來自多個源的行合併到單個結果集中時,它就會使用 Append
或 MergeAppend
計劃節點。這通常發生在實現 UNION ALL
或掃描分割槽表時。這些節點可以像在任何其他計劃中一樣在並行計劃中使用。然而,在並行計劃中,規劃器可能會改用 Parallel Append
節點。
當在並行計劃中使用 Append
節點時,每個程序將按出現順序執行子計劃,以便所有參與的程序協作執行第一個子計劃直到完成,然後大致同時移至第二個計劃。當改用 Parallel Append
時,執行器會將參與的程序儘可能均勻地分佈到其子計劃中,以便多個子計劃同時執行。這可以避免爭用,並且還可以避免那些從不執行它的程序支付子計劃的啟動成本。
此外,與只能在並行計劃中使用時具有部分子節點的常規 Append
節點不同,Parallel Append
節點可以同時具有部分和非部分子節點。非部分子節點將僅由一個程序掃描,因為多次掃描它們會產生重複的結果。因此,即使在沒有高效部分計劃可用時,涉及追加多個結果集的計劃也可以實現粗粒度並行。例如,考慮一個針對分割槽表的查詢,該查詢只能透過使用不支援並行掃描的索引來高效實現。規劃器可能會選擇常規 Index Scan
計劃的 Parallel Append
;每個單獨的索引掃描都必須由一個程序完整執行,但是不同的掃描可以由不同的程序同時執行。
可以使用 enable_parallel_append 來停用此功能。
如果一個預期會生成並行計劃的查詢沒有生成並行計劃,您可以嘗試降低 parallel_setup_cost 或 parallel_tuple_cost。當然,這個計劃可能比規劃器偏好的序列計劃慢,但這並不總是如此。即使使用非常小的值(例如,將兩者都設定為零)也未獲得並行計劃,原因可能是查詢規劃器無法為您的查詢生成並行計劃。有關原因,請參閱 第 15.2 節 和 第 15.4 節。
在執行並行計劃時,您可以使用 EXPLAIN (ANALYZE, VERBOSE)
來顯示每個計劃節點的每工作程序統計資訊。這有助於確定工作是否在所有計劃節點之間均勻分佈,以及更普遍地瞭解計劃的效能特徵。
如果您在文件中發現任何不正確、與您對特定功能的使用體驗不符或需要進一步闡述的內容,請使用 此表單 報告文件問題。