支援的版本:目前 (17) / 16 / 15 / 14 / 13
開發版本:devel
不支援的版本:12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1

50.5. 規劃器/最佳化器 #

規劃器/最佳化器的工作是建立一個最佳的執行計畫。給定的 SQL 查詢(以及因此產生的查詢樹)實際上可以用多種不同的方式執行,每種方式都會產生相同的結果集。如果計算上可行,查詢最佳化器將檢查每個可能的執行計畫,最終選擇預期執行速度最快的執行計畫。

注意

在某些情況下,檢查查詢可以執行的每種可能方式將花費過多的時間和記憶體。特別是,當執行涉及大量連接操作的查詢時,就會發生這種情況。為了在合理的時間內確定合理的(不一定是最佳的)查詢計畫,當連接的數量超過閾值時,PostgreSQL 使用基因查詢最佳化器(請參閱第 60 章)(請參閱geqo_threshold)。

規劃器的搜尋程序實際上使用稱為路徑的資料結構,這些路徑只是計畫的簡化表示,僅包含規劃器做出決策所需的資訊。在確定最便宜的路徑之後,會建立一個完整的計畫樹,以傳遞給執行器。這表示所需的執行計畫,其詳細程度足以讓執行器執行它。在本節的其餘部分,我們將忽略路徑和計畫之間的區別。

50.5.1. 產生可能的計畫 #

規劃器/最佳化器首先產生掃描查詢中使用之每個個別關係(表格)的計畫。可能的計畫由每個關係上可用的索引決定。始終存在對關係執行循序掃描的可能性,因此始終會建立循序掃描計畫。假設在關係上定義了索引(例如 B 樹索引),並且查詢包含限制 relation.attribute OPR constant。如果 relation.attribute 恰好與 B 樹索引的索引鍵相符,並且 OPR 是索引的運算子類別中列出的運算子之一,則會建立另一個計畫,使用 B 樹索引掃描關係。如果存在更多索引,並且查詢中的限制恰好與索引的索引鍵相符,則將考慮更多計畫。也為具有排序順序的索引產生索引掃描計畫,該排序順序可以符合查詢的 ORDER BY 子句(如果有的話),或可能對合併連接有用的排序順序(請參閱下文)。

如果查詢需要連接兩個或多個關係,則在找到掃描單個關係的所有可行計畫後,將考慮連接關係的計畫。三種可用的連接策略是

  • 巢狀迴圈連接:對於在左關係中找到的每一列,掃描一次右關係。此策略易於實作,但可能非常耗時。(但是,如果可以使用索引掃描掃描右關係,這可能是一個好策略。可以使用左關係的目前列中的值作為右關係的索引掃描的索引鍵。)

  • 合併連接:在連接開始之前,每個關係都會根據連接屬性進行排序。然後平行掃描兩個關係,並組合符合的列以形成連接列。這種連接很有吸引力,因為每個關係只需要掃描一次。所需的排序可以透過明確的排序步驟來實現,也可以透過使用連接鍵上的索引以正確的順序掃描關係來實現。

  • 雜湊連接:首先掃描右關係並將其載入雜湊表格中,使用其連接屬性作為雜湊鍵。接下來掃描左關係,並使用找到的每一列的適當值作為雜湊鍵,以在表格中找到符合的列。

當查詢涉及兩個以上的關係時,最終結果必須透過連接步驟的樹狀結構建立,每個步驟都有兩個輸入。規劃器檢查不同的可能連接順序以找到最便宜的順序。

如果查詢使用的關聯少於 geqo_threshold 個,則會進行近乎詳盡的搜尋,以找到最佳的連接順序。規劃器會優先考慮任意兩個關聯之間的連接,前提是在 WHERE 條件中存在對應的連接子句(也就是說,存在類似 where rel1.attr1=rel2.attr2 的限制)。只有在沒有其他選擇的情況下,才會考慮沒有連接子句的連接配對,也就是說,特定關聯沒有任何可用的連接子句連接到任何其他關聯。規劃器會為每個考慮的連接配對生成所有可能的計畫,並選擇(估計)成本最低的計畫。

當超過 geqo_threshold 時,所考慮的連接順序由啟發式方法決定,如第 60 章所述。否則,流程相同。

完成的計畫樹包含基本關聯的循序或索引掃描,以及所需的巢狀迴圈、合併或雜湊連接節點,以及任何所需的輔助步驟,例如排序節點或聚合函數計算節點。大多數這些計畫節點類型都具有執行選擇(捨棄不符合指定布林條件的列)和投影(基於給定的欄位值計算派生的欄位集,也就是說,在需要時評估純量表達式)的額外能力。規劃器的職責之一是將 WHERE 子句中的選擇條件和所需輸出表達式的計算附加到計畫樹中最合適的節點。

提交更正

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