?
本文檔使用 php中文網(wǎng)手冊 發(fā)布
規(guī)劃器/優(yōu)化器(planner/optimizer)的任務(wù)是創(chuàng)建一個優(yōu)化了執(zhí)行規(guī)劃。 一個特定的 SQL 查詢(因此也就是一個查詢樹)實際上可以以多種不同的方式執(zhí)行, 每種都生成相同的結(jié)果集。如果可能,查詢優(yōu)化器將檢查每個可能的執(zhí)行規(guī)劃, 最終選擇認為運行最快的執(zhí)行計劃。
Note: 有些情況下,檢查一個查詢所有可能的執(zhí)行方式會花去很多時間和內(nèi)存空間。 特別是在正在執(zhí)行的查詢涉及大量連接操作的時候。 為了在合理的時間里判斷一個合理的(而不是優(yōu)化的)查詢計劃。 PostgreSQL 使用基因查詢優(yōu)化器(Genetic Query Optimizer)。 (seeChapter 50) when the number of joins exceeds a threshold (seegeqo_threshold).
規(guī)劃器的搜索過程實際上是與叫做paths的數(shù)據(jù)結(jié)構(gòu)一起結(jié)合運轉(zhuǎn)的, 這個數(shù)據(jù)結(jié)構(gòu)是一個很簡單的規(guī)劃的精簡版本,它只包括規(guī)劃器用來決策所必須的信息。 在找到最經(jīng)濟的路徑之后,就制作一個完整的規(guī)劃樹(plan tree)傳遞給執(zhí)行器。 它有足夠的詳細信息,代表著需要執(zhí)行的計劃,執(zhí)行器可以讀懂并運行之。 在本章剩余部分,將忽略路徑和規(guī)劃之間的區(qū)別。
規(guī)劃器/優(yōu)化器通過為掃描查詢里出現(xiàn)的每個關(guān)系(表)生成規(guī)劃, 可能的規(guī)劃是由每個關(guān)系上有哪些可用的索引決定的。 對一個關(guān)系總是可以進行一次順序查找,所以總是會創(chuàng)建只使用順序查找的規(guī)劃。 假設(shè)一個關(guān)系上定義著一個索引(例如 B-tree 索引), 并且一條查詢包含約束relation.attribute OPR constant。 如果relation.attribute碰巧匹配 B-tree 索引的關(guān)鍵字 并且OPR又是列出在索引的操作符類中的操作符中的一個, 那么將會創(chuàng)建另一個使用 B-tree 索引掃描該關(guān)系的規(guī)劃。 如果還有別的索引,而且查詢里面的約束又和那個索引的關(guān)鍵字匹配,則還會生成更多的規(guī)劃。
如果查詢要求鏈接兩個或兩個以上的關(guān)系,在掃描單一的關(guān)系時,所有可行的計劃被找到后,鏈接關(guān)系的計劃才會被考慮。有三種可能的連接策略:
嵌套循環(huán)連接(nested loop join): 對左邊的關(guān)系里面找到的每條行都對右邊關(guān)系進行一次掃描。 這個策略容易實現(xiàn),但是可能會很耗費時間。 但是,如果右邊的關(guān)系可以用索引掃描,那么這個可能就是個好策略。 可以用來自左邊關(guān)系的當前行的數(shù)值為鍵字進行對右邊關(guān)系的索引掃描。
融合排序連接(merge join): 在連接開始之前,每個關(guān)系都對連接字段進行排序。 然后對兩個關(guān)系并發(fā)掃描,匹配的行就組合起來形成連接行。 這種聯(lián)合更有吸引力,因為每個關(guān)系都只用掃描一次。 要求的排序步驟可以通過明確的排序步驟, 或者是使用連接鍵字上的索引按照恰當?shù)捻樞驋呙桕P(guān)系。
Hash 連接hash join: 首先掃描右邊的關(guān)系,并用連接的字段作為散列鍵字加載進入一個 Hash 表, 然后掃描左邊的關(guān)系,并將找到的每行用作散列鍵字來以定位表里匹配的行。
如果查詢里的關(guān)系多于兩個,最后的結(jié)果必須通過一個連接步驟樹建立,每個步驟有兩個輸入。 規(guī)劃器檢查不同的連接順序可能,找出開銷最小的。
如果查詢使用了比geqo_threshold少的關(guān)系,為了找到最好的接入序列,near-exhaustive查找被運行。 策劃者優(yōu)先考慮接入任意兩個關(guān)系之間,那些在WHEREqualification里存在一個相應(yīng)的加入條款(例如: 存在像where rel1.attr1=rel2.attr2這樣的關(guān)系)。只有在沒有別的選擇的時候考慮加入對時沒有join字句, 也就是,一個特別的關(guān)系對另外的關(guān)系沒有可用的join子句。策劃者會為每一個加入對想到所有可能的計劃,選擇計劃的標準之一是(估計是)選擇最便宜的。
當geqo_threshold被超過,啟發(fā)式?jīng)Q定加入序列的考慮,就像在 Chapter 50里的描述。否則進程是一樣的。
完成的查詢樹由對基礎(chǔ)關(guān)系的順序或者索引掃描組成, 并根據(jù)需要加上嵌套循環(huán)、融合、以及 Hash 連接節(jié)點,加上任何需要的輔助步驟, 比如排序節(jié)點或者聚集函數(shù)計算節(jié)點等。 大多數(shù)這些規(guī)劃節(jié)點類型都有額外的做選擇(selection) (拋棄那些不符合指定布爾條件的行)和投影(projection) (基于給出的字段數(shù)值計算一個派生出的字段集,也就是在需要時計算標量表達式)。 規(guī)劃器的一個責(zé)任是從WHERE子句中 附加選擇條件以及為規(guī)劃樹最合適的節(jié)點計算所需要的輸出表達式。