sql優化之邏輯優化

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

查詢語句可表示成一顆二叉樹,其中葉子表明關係,內部結點是運算符,表示左右子樹的鏈接關係,子樹是sql片斷或子表達式。根節點是最後運算的操做符。根節點運算以後,獲得的是sql查詢優化後的結果。這樣一棵樹就是查詢路徑。多個關係鏈接,鏈接順序不一樣,能夠得出多個相似的二叉樹。
查詢優化就是找出代價最小的二叉樹,即最優的查詢路徑。
每條路徑的生成,包括單表掃描,兩錶鏈接,多表鏈接順序,多表鏈接搜索空間等技術。算法

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

  • 子句局部優化:等價謂詞重寫where和having條件化簡
    一、等價謂詞重寫
    列舉常見的等價謂詞重寫(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規則,若是在字段創建了索引,就能夠用索引掃描代替原來的全表掃描。
    二、where,having和on條件化簡
    將having條件併入where條件,只有在sql語句中不存在group by條件或彙集函數的狀況下,才能having條件與where條件進行合併。去除冗餘括號,常量傳遞,消除死碼,表達式計算,等式變換,不等式變換,布爾表達式變換,利用索引。這幾項過於簡單,不作展開描述

  • 子句間關聯優化(子句與子句之間關聯的語義):外鏈接消除嵌套鏈接消除子查詢優化視圖重寫等都屬於子句間的關聯優化,由於它們的優化都須要藉助其餘子句,表定義或列屬性等信息
    一、外鏈接消除
    外鏈接是什麼?
    答:左外鏈接,右外鏈接,全外鏈接。鏈接過程當中,外鏈接的左右子樹不能互換。它的這種性質限制了優化器在選擇鏈接順序時可以考慮的表與表交換鏈接位置的優化方式。
    優化時將外鏈接轉換成內鏈接的意義
    答:查詢優化器在處理外鏈接操做時所須要執行的操做和時間多於內鏈接。優化器在選擇表的鏈接順序時,能夠有更多更靈活的選擇,從而能夠選擇更好的錶鏈接順序,加快查詢執行的速度。表的一些鏈接算法(如塊嵌套鏈接和索引循環鏈接等)將規模小的或篩選條件最嚴格的表做爲「外表」(放在鏈接順序的最前面,是多層循環體的外循環層),能夠減小沒必要要的IO開銷,極大地加快算法執行速度。
    外鏈接消除的條件
    答:where子句中與內表相關的條件知足「空值拒絕」
    二、嵌套鏈接消除
    嵌套鏈接及嵌套鏈接消除是什麼?
    答:當執行鏈接操做的次序不是從左到右逐個進行時,就說明這樣的鏈接表達式存在嵌套。如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;去掉括號對語義沒有影響,因此能夠消除。還有鏈接表達式只包括內鏈接,就能夠去掉括號。由於內鏈接表之間的次序能夠互換。若是是外鏈接,至多轉化成內鏈接,再消除。
    三、子查詢優化
    爲啥要執行子查詢優化?
    答:查詢優化器對子查詢通常採用嵌套執行方式,即對父查詢中的每一行,都執行一次子查詢,這樣子查詢會執行不少次。因此會讓查詢效率下降。所以對於子查詢的優化,可能帶來幾個數量級的查詢效率的提升。把子查詢變成鏈接操做以後,子查詢不用執行不少次。優化器能夠根據統計信息來選擇不一樣的鏈接方法和不一樣的鏈接順序。子查詢中的鏈接條件,過濾條件分別變成了父查詢的鏈接條件,過濾條件,優化器能夠對這些條件進行下推,以提升執行效率。
    何時子查詢只能單獨求解?
    答:若是子查詢出現彙集,group by,distinct,子查詢只能單獨求解,不能夠拉到上層。
    最多見的子查詢類型優化?
    答:常見子查詢格式有in類型,all/any/some類型,exists類型。
    四、視圖重寫
    創建視圖。

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

  • 其餘優化:根據一些規則對非SPJ作的其餘優化,根據硬件環境進行的並行查詢優化
相關文章
相關標籤/搜索