2025年9月25日: PostgreSQL 18 釋出!
支援的版本: 當前 (18) / 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

51.5. 查詢規劃器/最佳化器 #

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

注意

在某些情況下,檢查查詢的每種可能執行方式會花費過多的時間和記憶體。特別是當執行涉及大量連線操作的查詢時,這種情況會出現。為了在合理的時間內確定一個合理的(不一定是最佳的)查詢計劃,當連線數超過閾值時(參見 geqo_threshold),PostgreSQL 會使用 遺傳查詢最佳化器(參見 第 61 章)。

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

51.5.1. 生成可能的計劃 #

規劃器/最佳化器首先為查詢中使用的每個單獨關係(表)生成掃描計劃。可能的計劃由每個關係上可用的索引決定。關係上總是存在順序掃描的可能性,因此總是會建立一個順序掃描計劃。假設一個關係上定義了索引(例如 B-tree 索引),並且查詢包含限制 relation.attribute OPR constant。如果 relation.attribute 恰好匹配 B-tree 索引的鍵,並且 OPR 是索引的 運算子類 中列出的運算子之一,則會建立一個使用 B-tree 索引掃描關係的另一個計劃。如果存在其他索引,並且查詢中的限制恰好匹配索引的鍵,則會考慮進一步的計劃。對於具有可以匹配查詢 ORDER BY 子句(如果有)的排序順序的索引,或者可能對合並連線(如下文所述)有用的排序順序的索引,也會生成索引掃描計劃。

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

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

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

  • 雜湊連線:首先掃描右關係並將其載入到雜湊表中,使用其連線屬性作為雜湊鍵。然後掃描左關係,並使用找到的每一行的相應值作為雜湊鍵來定位雜湊表中的匹配行。

當查詢涉及三個或更多關係時,最終結果必須透過一系列連線步驟構建,每個步驟有兩個輸入。規劃器會檢查不同的連線順序以找到成本最低的。

如果查詢涉及的關係少於 geqo_threshold 個,將進行近乎窮舉的搜尋來查詢最佳連線順序。規劃器優先考慮任何兩個關係之間的連線,這些關係在 WHERE 條件中存在相應的連線子句(即,存在類似 where rel1.attr1=rel2.attr2 的限制)。只有在沒有其他選擇時才考慮沒有連線子句的連線對,也就是說,某個關係與其他關係沒有任何可用的連線子句。對於規劃器考慮的每個連線對,都會生成所有可能的計劃,並選擇(估計)成本最低的那個。

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

完成的計劃樹由基本關係的順序掃描或索引掃描組成,加上所需的巢狀迴圈、合併或雜湊連線節點,再加上任何輔助步驟,如排序節點或聚合函式計算節點。大多數這些計劃節點型別還具有執行 選擇(丟棄不滿足指定布林條件的行)和 投影(基於給定列值計算派生列集,即在需要時評估標量表達式)的能力。規劃器的職責之一是將 WHERE 子句中的選擇條件和所需的輸出表達式的計算附加到計劃樹的最合適節點。

提交更正

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