sql優化之邏輯優化

蒙奇D穎發表於2018-12-12

在單機資料庫系統中進行優化。面臨的問題,比如說給定一個要query的sql語句,查詢優化演算法的目標就是找到查詢的一個具有最小執行花費的執行計劃,如果找到了,那麼這樣的執行計劃一定具有最快的響應時間。

查詢語句可表示成一顆二叉樹,其中葉子代表關係,內部結點是運算子,表示左右子樹的連線關係,子樹是sql片段或子表示式。根節點是最後運算的操作符。根節點運算之後,得到的是sql查詢優化後的結果。這樣一棵樹就是查詢路徑。多個關係連線,連線順序不同,可以得出多個類似的二叉樹。
查詢優化就是找出代價最小的二叉樹,即最優的查詢路徑。
每條路徑的生成,包括單表掃描,兩表連線,多表連線順序,多表連線搜尋空間等技術。

思路一:邏輯優化,找出SQL語句等價的變換形式,使得sql執行更高效。優化操作依賴於表的一些屬性資訊(如索引和約束等)

  • 子句區域性優化:等價謂詞重寫where和having條件化簡
    1、等價謂詞重寫
    列舉常見的等價謂詞重寫(like規則,between-and規則,in轉換成or規則,NOT規則,or重寫Union規則,這些規則的前提是要查詢的欄位建立索引;or轉換any規則就是or謂詞的any等價重寫,以更好的利用min/max操作進行優化;all/any轉換min/max規則,>any等價於min,<all等價於max;)?
    答:like謂詞是sql標準支援的一種模式匹配比較操作,like規則是對like謂詞的等價重寫。如name like `Abc%`可以改寫成name>=`Abc` and name < `Abd`
    between-and謂詞是sql標準支援的一種範圍比較操作,between-and規則是指between-and謂詞的等價重寫。如sno between 10 and 20要重寫為sno>10 and sno <= 20
    此處的in是in操作符,不是in查詢。in轉換成or規則是將In謂詞轉換成等價的or謂詞,以更好的利用索引優化,如age in(8,12,21)重寫為age=8 or age=12 or age=21;
    NOT規則,如not(col_1 != 2)重寫為col_1=2;
    or重寫union規則,如SELECT * FROM student WHERE(sex=`f` AND sno>15) OR age>18;改寫成SELECT * FROM student WHERE sex=`f` and sno>15 UNION SELECT * FROM student WHERE age>18;
    all/any轉換min/max規則,如sno>any(10,2*5+3,sqrt(9)) 找其中的最小值 重寫為sno>min(10,2*5+3,sqrt(9));
    應用like規則和between-and規則,in轉換成or規則,not規則的好處是?
    答:轉換前對於like謂詞只能進行全表掃描,如果name列上存在索引,則轉換後可以進行索引範圍掃描。轉換前對於between-and謂詞限定的全表掃描,如果在sno上建立索引,可以用索引範圍掃描。in轉換or規則後效率能否提高,需要看資料庫對in謂詞是否只支援全表掃描。如果資料庫對In謂詞只支援全表掃描且or謂詞欄位存在索引,則使用轉換規則後效率會提高;not規則,如果在欄位建立了索引,就可以用索引掃描代替原來的全表掃描。
    2、where,having和on條件化簡
    將having條件併入where條件,只有在sql語句中不存在group by條件或聚集函式的情況下,才能having條件與where條件進行合併。去除冗餘括號,常量傳遞,消除死碼,表示式計算,等式變換,不等式變換,布林表示式變換,利用索引。這幾項過於簡單,不做展開描述

  • 子句間關聯優化(子句與子句之間關聯的語義):外連線消除巢狀連線消除子查詢優化檢視重寫等都屬於子句間的關聯優化,因為它們的優化都需要藉助其他子句,表定義或列屬性等資訊
    1、外連線消除
    外連線是什麼?
    答:左外連線,右外連線,全外連線。連線過程中,外連線的左右子樹不能互換。它的這種性質限制了優化器在選擇連線順序時能夠考慮的表與表交換連線位置的優化方式。
    優化時將外連線轉換成內連線的意義
    答:查詢優化器在處理外連線操作時所需要執行的操作和時間多於內連線。優化器在選擇表的連線順序時,可以有更多更靈活的選擇,從而可以選擇更好的表連線順序,加快查詢執行的速度。表的一些連線演算法(如塊巢狀連線和索引迴圈連線等)將規模小的或篩選條件最嚴格的表作為“外表”(放在連線順序的最前面,是多層迴圈體的外迴圈層),可以減少不必要的IO開銷,極大地加快演算法執行速度。
    外連線消除的條件
    答:where子句中與內表相關的條件滿足“空值拒絕”
    2、巢狀連線消除
    巢狀連線及巢狀連線消除是什麼?
    答:當執行連線操作的次序不是從左到右逐個進行時,就說明這樣的連線表示式存在巢狀。如select * from t1 left join(t2 left join t3 on t2.b = t3.b) on t1.a = t2.a where t1.a > 1;先t2與t3連線,得到中間結果{t2t3}後再與t1連線,去掉括號會影響語義。還有形如select * from a join (b join c on b.b1 = c.c1) on a.a1 = b.b1 where a.a1 > 1;去掉括號對語義沒有影響,所以可以消除。還有連線表示式只包括內連線,就可以去掉括號。因為內連線表之間的次序可以互換。如果是外連線,至多轉化成內連線,再消除。
    3、子查詢優化
    為啥要執行子查詢優化?
    答:查詢優化器對子查詢一般採用巢狀執行方式,即對父查詢中的每一行,都執行一次子查詢,這樣子查詢會執行很多次。所以會讓查詢效率降低。因此對於子查詢的優化,可能帶來幾個數量級的查詢效率的提高。把子查詢變成連線操作之後,子查詢不用執行很多次。優化器可以根據統計資訊來選擇不同的連線方法和不同的連線順序。子查詢中的連線條件,過濾條件分別變成了父查詢的連線條件,過濾條件,優化器可以對這些條件進行下推,以提高執行效率。
    什麼時候子查詢只能單獨求解?
    答:如果子查詢出現聚集,group by,distinct,子查詢只能單獨求解,不可以拉到上層。
    最常見的子查詢型別優化?
    答:常見子查詢格式有in型別,all/any/some型別,exists型別。
    4、檢視重寫
    建立檢視。

  • 語義優化:根據完整性約束,sql表達含義等資訊對語句進行語義優化
    語義優化有哪些
    groupby 優化
    1、分組操作下移 :groupby 操作可能較大幅度地減少關係元組的個數,如果能對某個關係先進行分組操作,再進行表的連線,會提高連線效率。這種優化方式是把分組操作提前執行。下移含義,是在查詢樹上讓分組操作儘量靠近葉子節點,使得分組操作的結點低於一些選擇操作。
    2、分組操作上移 :如果連線操作能夠過濾掉大部分元組,則先進行連線後進行groupby操作,可能提高分組操作效率。這種優化方式是把分組操作置後執行。
    order by優化
    排序消除,優化器在生成執行計劃之前,將語句中沒有必要的排序操作消除(利用索引),避免在執行計劃中出現排序操作或由排序導致的操作。
    排序下推,把排序操作儘量下推到基表中,有序的基表進行連線後的結果符合排序的語義,這樣能避免在最終的大的連線結果集上執行排序操作。
    distinct優化
    distinct消除:如果表中存在主鍵,唯一約束,索引等,則可以消除查詢語句中的distinct。
    distinct推入:生成含distinct的反半連線查詢執行計劃時,先進行反半連線再進行distinct操作,也許先執行distinct操作再執行反半連線更優,這是利用連線語義上確保唯一功能特性進行distinct的優化。
    distinct遷移:對連線操作的結果執行distinct,可能把distinct移到一個子查詢中優先進行。

  • 其他優化:根據一些規則對非SPJ做的其他優化,根據硬體環境進行的並行查詢優化

相關文章