40.5. 規劃器/優化器

規劃器/優化器的任務是建立一個優化了執行規劃。 一個特定的 SQL 查詢(因此也就是一個查詢樹)實際上可以以多種不同的方式執行, 每種都生成相同的結果集。如果可能,查詢優化器將檢查每個可能的執行規劃,最終選擇認為執行最快的執行計劃。

注意: 有些情況下,檢查一個查詢所有可能的執行方式會花去很多時間和內存空間。 特別是在正在執行的查詢涉及大量連接操作的時候。為了在合理的時間裡判斷一個合理的(而不是優化的)查詢計劃。 PostgreSQL 使用 基因查詢優化

規劃器的搜索過程實際上是與叫做 paths 的資料結構一起結合運轉的, 這個資料結構是一個很簡單的規劃的精簡版本,它只包括規劃器用來決策所必須的訊息。 在找到最經濟的路徑之後,就製作一個完整的規劃樹傳遞給執行器。 它有足夠的詳細訊息,代資料表著需要執行的計劃,執行器可以讀懂並執行之。 在本章剩餘部分,我們將忽略路徑和規劃之間的區別。

40.5.1. 生成可能的規劃

規劃器/優化器透過為掃瞄查詢裡出現的每個關係(資料表)生成規劃, 可能的規劃是由每個關係上有哪些可用的索引決定的。 對一個關係總是可以進行一次順序查找, 所以總是會建立只使用順序查找的規劃。 假設一個關係上定義著一個索引(例如 B-tree 索引), 並且一條查詢包含約束 relation.attribute OPR constant。如果 relation.attribute 碰巧匹配 B-tree 索引的關鍵字並且 OPR 又是列出在索引的操作符資料表中的操作符中的一個, 那麼將會建立另一個使用 B-tree 索引掃瞄該關係的規劃。 如果還有別的索引, 而且查詢裡面的約束又和那個索引的關鍵字匹配,則還會生成更多的規劃。

在尋找完掃瞄一個關係的所有可能的規劃後, 接著建立連線各個關係的規劃。 規劃器/優化器首先考慮在 WHERE 條件裡存在連接子句的連接(比如,存在象 where rel1.attr1=rel2.attr2 這樣的約束)。 沒有連接子句的的連接對只有在沒有別的選擇的時候才考慮,也就是說, 一個關係沒有和任何其它關係的連接子句可用。 規劃器/優化器為它們認為可能的所有的連接關係對生成規劃。 有三種可能的連接策略:

如果查詢裡的關係多於兩個,最後的結果必須透過一個連接步驟樹建立, 每個步驟有兩個輸入。規劃器檢查不同的連接順序可能,找出開銷最小的。

完成的查詢樹由對基礎關係的順序或者索引掃瞄組成,並根據需要加上嵌套循環, 融合,或者散列連接節點,加上任何需要的輔助步驟,比如排序節點或者聚集函數計算節點等。 大多數這些規劃節點類型都有額外的做選擇(拋棄那些不符合指定布爾條件的行)和投影 (基於給出的字串數值,計算一個派生出的字串集,也就是,在需要時計算標量資料表達式)。 規劃器的一個責任時從 WHERE 子句中附加選擇條件以及為規劃樹最合適的節點計算所需要的輸出資料表達式。