MySql學習(六) —— 數據庫優化理論(二) —— 查詢優化技術


 

邏輯查詢優化包括的技術

  1)子查詢優化  2)視圖重寫  3)等價謂詞重寫  4)條件簡化  5)外連接消除  6)嵌套連接消除  7)連接消除  8)語義優化 9)非SPJ優化

 

一、子查詢優化

  1. 什么是子查詢:當一個查詢是另一個查詢的子部分時,稱之為子查詢。

  2. 查詢的子部分,包含的情況:

    a) 目標列位置:子查詢如果位於目標列,則只能是標量子查詢,否則數據庫可能返回類似“錯誤:子查詢只能返回一個字段 ( [Err] 1242 - Subquery returns more than 1 row )”的提示。

    b) FROM子句位置:相關子查詢出現在FROM子句中,數據庫可能返回類似“錯誤:在FROM子句中的子查詢無法參考相同查詢級別中的關系”的提示,所以相關子查詢不能出現在FROM子句中(即FROM型子查詢不能與外面的查詢有任何的關聯)。

      非相關子查詢出現在FROM子句中,可上拉子查詢到父層,在多表連接時統一考慮連接代價然后擇優。

      

    c) WHERE子句位置:出現在WHERE子句中的子查詢,是一個條件表達式的一部分,而表達式可以分解為操作符和操作數;根據參與運算的不同的數據類型,操作符也不盡相同,如int型有“>、<、=、<>”等操作;這對子查詢就有了一定的要求,如int型的等值操作,要求子查詢必須是標量子查詢。另外,子查詢出現在WHERE子句中的格式,也有用謂詞指定的一些操作,如“in、between... 、exists”等。

    d) JOIN/ON子句位置:JOIN/ON子句可以拆分為兩部分,一是JOIN塊類似於FROM子句,二是ON子句塊類似於WHERE子句,這兩部分都可以出現子查詢。子查詢的處理方式同FROM子句和WHERE子句。

    e) GROUP BY子句位置:目標列必須和GROUP BY 關聯,可將子查詢寫在GROUP BY位置處,但子查詢用在GROUP BY處沒有實用意義。

    f) ORDER BY子句位置:可將子查詢寫在ORDER BY位置處。但ORDER BY操作是作用在整條SQL語句上的,子查詢用在ORDER BY處沒有實用意義。

  3.子查詢的類型——從對象間的關系看

    a) 相關子查詢:子查詢的執行依賴於外層父查詢的一些屬性值。子查詢因依賴於父查詢的參數,當父查詢的參數改變時,子查詢需要根據新參數值重新執行(查詢優化器對相關子查詢進行優化有一定意義)。

       

    b) 非相關子查詢:子查詢的執行,不依賴於外層父查詢的任何屬性值。這樣子查詢具有獨立性,可獨自求解,形成一個子查詢計划先於外層的查詢求解。

  4.子查詢的類型——從特定謂詞看

    a) [NOT] IN / ALL / ANY / SOME 子查詢:語義相近,左邊是操作數,右邊是子查詢,是最常見的子查詢類型之一。

    b) [NOT] EXISTS 子查詢:半連接語義,沒有左操作數,右邊是子查詢,是常見的子查詢之一。

  5.子查詢的類型——從語句的構成復雜程度看

    a) SPJ子查詢:由選擇(Select)、投影(Projection)、連接(Join)操作組成的查詢

    b) GROUP BY子查詢:SPJ子查詢加上分組、聚集操作組成的查詢。

    c) 其它子查詢:GROUP BY子查詢中加上其它子句如Top-N,LIMIT / OFFSET 、集合、排序等操作。

  6.子查詢的類型——從結果的角度看

    a) 標量子查詢:子查詢返回的結果集類型是一個簡單值

    b) 單行單列子查詢:子查詢返回的結果集類型是零條或一條單元組。相似於標量子查詢,但可能返回零條元組。

    c) 多行單列子查詢:子查詢返回的結果集類型是多條元組但只有一個簡單列。

    d) 表子查詢:子查詢返回的結果集類型是一個表(多行多列)。

  7.為什么要作子查詢優化呢?

    在數據庫實現早期,查詢優化器對子查詢一般采用嵌套執行的方式,即對父查詢中的每一行,都執行一次子查詢,這樣子查詢會執行很多次。這種執行方式效率很低。

    對子查詢進行優化,可能帶能幾個數量級的查詢效率的提高。

    子查詢轉變為連接操作之后,會得到如下好處:a) 子查詢不用執行很多次; b) 優化器可以根據統計信息來選擇不同的連接方法和不同的連接順序。

    子查詢的連接條件、過濾條件分別變成了父查詢的連接條件、過濾條件,優化器可以對這些條件進行下推,以提高執行效率。

  8.子查詢優化方式

    a) 子查詢合並:在某些條件下(語義等價:兩個查詢塊產生同樣的結果集(列一致) ),多個子查詢能夠合並成一個子查詢(合並后還是子查詢,以后可以通過其它技術消除掉子查詢)。這樣可以把多次表掃描、多次連接 減少為單次表掃描和單次連接。

    b) 子查詢展開:又稱子查詢反嵌套,或稱為子查詢上拉

      把一些子查詢置於外層的父查詢中,作為連接關系與外層父查詢並列,其實質是把某些子查詢重寫為等價的多表連接操作(展開后,子查詢不存在了,外部查詢變成了多表連接)。

      帶來的好處是:有關的訪問路徑、連接方法和連接順序可能被有效使用,使得查詢語句的層次盡可能的減少。

      常見的IN / ANY / ALL / SOME / EXISTS 依據情況轉變為半連接(SEMI JOIN),普通的子查詢消除等情況屬於此類。

    c) 聚集子查詢消除:通常,一些系統支持的是標量聚集子查詢消除。

 

  9.MySQL子查詢優化(MySQL優化器優化)

    1.MySql可以優化什么格式的子查詢

      1) 優化器支持對簡單SELECT查詢中的子查詢優化:

        a) 簡單select中的子查詢,會被mysql優化器自動上拉到父層。

        b) 帶有DISTINCT、ORDER BY、LIMIT操作的簡單SELECT查詢中的子查詢。 

      2) 優化器不支持對如下情況的子查詢進行優化

        a) 帶有UNION操作。

        b) 帶有GROUP BY、HAVING、聚集函數。

        c) 使用ORDER BY中帶有LIMIT。

        d) 內表、外表的個數超過MySql支持的最大的表連接數。

    2.MySql支持哪些子查詢的優化技術

      1) 不支持子查詢合並技術

      2) 不能很好的支持子查詢展開(子查詢上拉)技術

      3) 不支持聚集子查詢消除技術:MySQL認為聚集子查詢只需要執行一次,得到結果后,把結果緩沖到內存中以供后續連接或過濾操等操作使用,沒必要消除子查詢。另外,如果聚集子查詢在索引列上執行,則會更快得到查詢結果,更能加快查詢速度。

    3.MySQL支持對哪些類型的子查詢進行優化 

      1) 不支持對EXISTS類型的子查詢做進一步的優化(上拉子查詢)。

      2) 支持對IN類型的子查詢的優化,in子查詢被優化為半連接。

        3) 支持對NOT IN 類型的子查詢的優化,NOT IN 子查詢被物化,但沒有消除子查詢。

      4) 支持對< ALL類型的子查詢的優化,< ALL子查詢被轉換為<not> >= MAX運算。

      5) 支持對> ALL類型的子查詢的優化,> ALL子查詢被轉換為<not> <= MIN運算

      5) 支持對= ALL類型的子查詢的優化,= ALL子查詢優化為用“EXISTS strategy”方式優化。

 

二、視圖重寫

  1.什么是視圖重寫?

    1) 查詢語句中出現視圖對象(先將視圖轉化為子查詢,再進行優化)

    2) 查詢優化后,視圖對象消失

    3) 消失的視圖對象的查詢語句,融合到初始查詢中

  2.MySQL視圖重寫准則

    1) MySQL支持對視圖進行優化

    2) 優化方法是把視圖轉為對基表的查詢,然后進行類似於子查詢的優化。

    3) MySQL通常只能重寫簡單視圖(SPJ簡單查詢的視圖),復雜視圖(非SPJ查詢,如帶有GROUP BY的視圖)不能重寫。

 

三、等價謂詞重寫

  等價謂詞重寫(主要就是使其能更好的利用索引,有些謂詞是可以利用索引的)

    1) 把邏輯表達式重寫成等價的且效率更高的形式。

    2) 優點:能有效提高查詢執行效率

    3) LIKE 規則

      LIKE規則,是對LIKE謂詞的等價重寫,即改寫LIKE謂詞為其它等價的謂詞,以更好地利用索引進行優化。

      例如:name LIKE "ABC%" => 重寫為 name >= "ABC" AND name < "Abd"

      應用LIKE規則的好處:轉換前針對LIKE謂詞,只能進行全表掃描,如果name列上存在索引,則轉換后可以進行索引掃描。

      另外,LIKE后的表達式,如果左邊有通配符("%xxx%"),無法利用索引掃描;如果左邊沒有通配符("xxx%"),是可以利用索引進行掃描的。

    4) BETWEEN-AND規則

      改寫between-and謂詞為其它等價的謂詞,以便更好的利用索引進行優化。

      例如:number BETWEEN 10 AND 20 => 重寫為:number >= 10 AND number <= 20

      好處:如果建立了索引,則可以利用索引掃描代替between-and謂詞限定的全表掃描,從而提高了效率。

    5) IN 轉換OR規則

      IN 指IN操作符操作,不是IN子查詢。

      如果IN不支持索引,而IN對應的列又有索引,將IN謂詞等價重寫為若干個OR謂詞,可能會提高執行效率。

      IN 可以轉換為OR,OR可以轉為ANY,所以可以直接把IN轉換為ANY。將IN謂詞等價重寫為ANY謂詞,可能會提高效率。

      應用IN轉換為ANY后效率是否能提高,依賴於數據庫對於ANY操作的支持情況。

    6) OR 轉換ANY規則

      OR轉換為ANY,如果數據庫支持,可以更好地利用MIN/MAX操作進行優化。(MySql5.6不支持)

    7) ALL/ANY 轉換為聚集函數

      ALL/ANY轉換為等價的聚集函數MIN/MAX,以更好的利用MIN/MAX操作進行優化。

      通常,聚集函數MAX()/MIN()等的執行效率一般都比ANY、ALL謂詞的執行效率高,如果有索引存在,求解MAX/MIN的效率更高。

    8) NOT謂詞的等價重寫

      NOT(col != 2) =>  col = 2

      NOT(col = col2) =>  col != col2

      NOT(col > 2)  => col <= 2

      如果NOT操作的列上建立了索引,則可以用索引掃描代替原來的全表掃描,從而提高效率。

    9) OR重寫並集規則

      為了能更好利用索引處理多個OR連接的查詢,可以使用UNION分別求解然后合並結果集,這樣可以快速利用索引進行掃描。(前提是OR對應的列有索引)

      SELECT * FROM tt WHERE c1 > 100 OR c2 < 10;  =>  SELECT * FROM tt WHERE c1 > 100 UNION (SELECT * FROM tt WHERE c2 < 10)

 

四、條件化簡(條件優化技術)

  SQL語句中,條件分為對元組過濾的條件和對連接操作的過濾條件(即什么樣的連接方式)

  1.條件下推

    把與單個表相關的條件,放到對單表進行掃描的過程中分析。

    數據庫系統都支持條件下推,且無論條件對應的列對象有無索引,系統自動進行優化,不用人工介入。

    例如:SELECT * FROM A, B WHERE A.id < 10 AND A.m = B.m;  

      => 執行順序:1.掃描A表,並帶有A.id < 10 ,把A表作為嵌套循環的外表; 2.掃描B表,執行連接操作,並帶有過濾條件A.m = B.m;不管兩個條件的順序如何,都會被下推成這個順序。

  2.條件化簡

    1) WHERE、HAVING、JOIN-ON條件由許多表達式組成,而這些表達式在某些時候彼此之間存在一定的聯系

    2) 利用等式和不等式的性質,可以將WHERE、HAVING和ON條件化簡。

    3) 不同數據庫的實現可能不完全相同。

    4) 具體實現:

      a) 把HAVING條件並入WHERE條件(優化器不支持,自己轉換)

        優點:便於統一、集中化簡條件子句,節約多次化解時間。

        注意:不是任何情況下HAVING條件都可以並入WHERE條件,只有在SQL語句中不存在GROUP BY條件或聚集函數的情況下,才能將HAVING條件和WHERE條件進行合並。

        例子:SELECT * FROM t WHERE a > 5 HAVING b < 10  =》  SELECT * FROM t WHERE a > 5 AND b < 10;

      b) 去除表達式中的冗余括號(支持)

        優點:可以減少語法分析時產生的AND和OR樹的層次,減少CPU的消耗

      c) 常量傳遞(支持)

        優點:對不同關系可以使得條件分離后有效實施“選擇下推”,從而可以極大減小中間關系的規模;可以減少語法分析時間,因為會被優化器  優化成條件分離的形式。       

        例子:SELECT .... ... WHERE a = b AND a = 1;  =》  SELECT ... ... WHERE a = 1 AND b = 1;

        注意:操作符“=、<、>、<=、>=、<>、<=>、LIKE”中的任何一個,在“a [操作符] b”條件中都可能會發生常量傳遞。

      d) 消除死碼(支持)

        優點:化簡條件,將不必要的條件去除。

      e) 表達式計算(支持)

        對可以求解的表達式先進行計算,得出結果。

        例子:WHERE a = 1+2  =》  WHERE a = 3

      f) 等式變換(不支持,自己轉換)

        化簡條件,如反轉關系操作符的操作數的順序,從而改變某些表的訪問路徑。

        例子:WHERE -a = 3  =》 WHERE a = -3

        優點:如果a 上有索引,則可以利用索引掃描來加快訪問。

      g) 不等式變換(不支持)

        化簡條件,將不必要的重復條件去除。

      h) 布爾表達式變換

        優點:減少條件連接時的元組。

        1.謂詞傳遞閉包(不支持,自己轉換)

          一些比較操作符如“<、>”等,具有傳遞性,可以起到化簡表達式的作用

          例子:a > b AND b > 2  =》  a > b AND b > 2 AND a > 2;這里 a > 2 是一個隱藏條件。這樣把a > 2 和 b > 2分別下推到對應的關系上,就可以減少參與比較操作 a > b 的元組數了。

        2.布爾表達式被轉換為一個等價的合取范式(CNF) (支持)

          任何一個布爾表達式都能被轉換為一個等價的合取范式(CNF);

          合取范式格式為:c1 AND c2 AND ... AND cn ;其中,ck 稱為合取項(1 < k < n),每個合取項是不包含AND的布爾表達式(即每個表達式不再嵌套AND條件)。

          優點:

            ①合取項只要有一個為假,整個表達式就為假,故代碼中可以在發現一個合取項為假時,即停止其它合取項的判斷,加快判斷速度。

            ②因為AND操作符是可以交換的,所以優化器可以按照先易后難的順序計算表達式,一旦發現一個合取項為假時,即停止其它合取項的判斷,加快判斷速度。

        3.索引利用(支持)

          如果一個合取項上存在索引,則先判斷索引是否可用,如果能利用索引快速得出合取項的值,則能加快判斷速度。同理,OR表達式中的子項也可以利用索引。

          

 

五、外連接消除、嵌套連接消除、連接消除

  外連接:LEFT [OUTER] JOIN ... ON ... / RIGHT [OUTER] JOIN ... ON ... 

  內連接:[INNER] JOIN ... ON ...

  1.外連接消除(即左右連接及全連接)

    1)為什么要進行外連接消除

      a) 查詢優化器在處理外連接操作時所需執行的操作和時間多余內連接。

      b) 外連接消除后,優化器在選擇多表連接順序時,可以有更多更靈活的選擇,從而可以選擇更好的表連接順序,加快查詢執行的速度。

      c) 表的一些連接算法(如塊嵌套連接和索引循環連接等)在將規模小的或篩選條件最嚴格的表作為“外表”(放在連接順序的最前面,是多層循環體的外層循環),可以減少不必要的IO開銷,能加快算法執行的速度。

      d) 外連接消除去掉的是外連接的語義,變形為內連接。 

    2)外連接消除的條件

       外連接消除,把外連接變為內連接:A LEFT/RIGHT JOIN B ON  =》  A JOIN B

       WHERE 子句中的條件滿足“空值拒絕”(“reject-NULL”條件):

        WHERE條件可以保證從結果中排除外連接右側(右表)生成的值為NULL的行(即條件確保應用在右表帶有空值的列對象上時,條件不滿足,條件的結果值為FALSE或UNKNOWEN,這樣右表就不會有值為NULL的行生成),所以能使該查詢在語義上等效於內連接。但左表不滿足條件的數據也不會查出來,小心使用。

        例子:下面四個例子的效果一樣,都能保證右表不為空,從而等效於內連接、。

          SELECT * FROM A LEFT JOIN B ON A.m = B.m WHERE B.m IS NOT NULL;

          SELECT * FROM A LEFT JOIN B ON true WHERE A.m = B.m;

          SELECT * FROM A LEFT JOIN B ON A.m = B.m WHERE A.m = B.m;

          SELECT * FROM A LEFT JOIN B ON A.m = B.m WHERE B.col <expression>; WHERE條件后如果有跟右表相關的條件也會被優化成內連接(因為如果不滿足連接條件,右表每列都為NULL了,保證了不會有空行出現)。

  2.連接消除

    去掉不必要的連接對象,則減少了連接操作。

    消除情況:

    1) 唯一鍵/主鍵作為連接條件,三表內連接可以去掉中間表(中間表的列只作為連接條件),可以消除主鍵表。

      例子:SELECT A.*, C.* FROM A, B, C WHERE A.a = B.a AND B.a = C.a;  =》 SELECT A.*, C.* FROM A, C WHERE A.a = C.a;

    2) 一些特殊的形式,可以消除連接操作(可消除的表除了作為連接對象外,不出現在任何子句中)

      例子:SELECT A.a FROM A, B; 可消除B表

  3.嵌套連接消除

    連接存在多個層次,用括號標識連接的優先次序。

    嵌套連接消除,就是消除嵌套的連接層次(去掉括號),把多個層次的連接減少為較少層次的連接,盡量“扁平化”。

    嵌套連接消除的是連接的層次,這是一種連接的語義順序的變化。

 

 六、數據庫的約束規則與語義優化

  1.數據完整性(Data Integrity)

    指數據的精確性(Accuracy)和可靠性(Reliability)。

    作用:1.防止用戶向數據庫中添加不合語義的數據。2.利用基於DBMS的完整性控制機制來實現業務規則,易於定義,容易理解,而且可以降低應用程序的復雜性,提高應用程序的運行效率。同時,基於DBMS的完整性控制機制是集中管理的,因此此應用程序更容易實現數據庫的完整性。

    數據完整性分為四類:

      1)實體完整性(Entity Integrity):自己

        一個關系對應現實世界中的一個實體集。——ER模型

        現實世界中的實體具有某種唯一性標識。——主鍵

        主關鍵字是多個屬性的組合,則所有主屬性均不得取控制。——隱含的索引。

      2)域完整性(Domain Integrity):自己的局部(字段)

        保證數據庫字段取值的合理性

        屬性值應是域中的值:檢查(check)、默認值(default)、不為空(not null)、可為空(null)等等。

      3)參照完整性(Referential Integrity):自己與其它實體的關系(主外鍵)

        參照完整性是定義建立在關系之間聯系的主關鍵字與外部關鍵字引用的約束條件。

      4)用戶自定義完整性(User-defined Integrity):用戶增加的限制(如非空約束等)

  2.語義優化

    1.語義轉換:因為完整性限制等的原因使得一個轉換成立的情況稱為語義轉換。

    2.語義優化:因為語義轉換形成的優化稱為語義優化

      語義轉換其實是根據完整性約束等信息對“某特定語義”進行推理,進而得到一種查詢效率不同但結果相同的查詢。

      語義優化是從語義的角度(SQL語句所表達的含義、意義)對SQL進行優化,不是一種形式上的優化,所以其優化的范圍,可能覆蓋其它類型的優化范圍。根據完整性約束,對查詢語句進行語義理解,推知一些可優化的操作。

    3.語義優化常見的方式

      1) 連接消除:對一些連接操作先不必評估代價,根據已知信息(主要依據完整性約束等,但不全是依據完整性約束)能推知結果或得到一個簡化的操作。

      2) 連接引入:增加連接有助於原始關系變小或原關系的選擇率降低。

      3) 謂詞引入:根據完整性約束信息,引入新謂詞,如引入基於索引的列,可能使得查詢更快。

      4) 檢測空集回答:查詢語句中的謂詞與約束相悖,可以推知條件結果為FALSE,也許最終的結果集能為空。(如:a 列限制在100-200之間,查詢a < 90則能立即推知條件不成立)

        5) 排序優化:ORDER BY操作通常由索引和排序(set)完成,如果能夠利用索引,則排序操作可省略;另外,結合分組等操作,考慮ORDER BY操作的優化。

      6) 唯一性使用:利用唯一性、索引等特點,檢查是否存在不必要的DISTINCT等操作。

 

七、非SPJ優化

  1.GROUP BY優化

    1) 分組轉換技術:對分組操作、聚集操作與連接操作的位置進行交換

      a) 分組操作下移:GROUP BY操作可能較大幅度減少關系元組的個數,如果能夠對某個關系先進行分組操作,然后再進行表之間的連接,很可能提高連接效率。這種優化方式是把分組操作提前執行。下移的含義,是在查詢樹上,讓分組操作盡量靠近葉子節點,使得分組操作的節點低於一些選擇操作。

      b) 分組操作上移:如果連接操作能夠過濾掉大部分元組,則先進行連接操作,后進行GROUP BY操作,可能提高分組操作的效率。這種優化方式是把分組操作置后執行。上移的含義和下移相反。 

    2) MySQL的GROUP BY優化:MySQL對於GROUP BY的處理,通常采用的方式是掃描整個表、創建一個臨時表以執行分組操作。MySQL不支持分組轉換技術。對於GROUP BY的優化,盡量利用索引。

      利用索引的條件:分組子句中的列對象源自同一個BTREE索引(不支持利用HASH索引進行優化)的全部或前綴部分的部分有序的鍵(分組使用的索引列與索引建立的順序不匹配則不能使用索引)。     

  2.ORDER BY優化

    ORDER BY 如果操作的列不是主鍵或索引等,會創建一個臨時表(Using temporary、Using flesort)

    1) 排序消除:優化器在生成執行計划前,將語句中沒有必要的排序操作消除(如利用索引),避免在執行計划中出現排序操作或由排序導致的操作(如在索引列上排序,可以利用索引消除排序操作)

    2) 排序下推:把排序操作盡量下推到基表中,有序的基表進行連接后的結果符合排序的語義,這樣能避免在最終的大的連接結果集上執行排序操作。

  3.DISTINCT優化

    DISTINCT操作的列,如果該列有索引(唯一性約束)或者為主鍵,則直接使用索引排序;否則會使用一張臨時表(Using temporary),先去重,再排序(可以看到輸出結果是根據該列排好序的)。

    1) DISTINCT消除:如果表中存在主鍵、唯一約束、索引等,則可以消除查詢語句中的DISTINCT 

    2) DISTINCT推入:生成含DISTINCT的反半連接查詢執行計划時,先進行反半連接再進行DISTINCT操作;也許先執行DISTINCT操作再執行反半連接,可能更優。

    3) DISTINCT遷移:對連接操作的結果執行DISTINCT,可能把DISTINCT移到一個子查詢中優先進行

  總結:GROUP BY / ORDER BY / DISTINCT 優化盡量利用索引、主鍵、唯一性約束,這樣可以不創建臨時表。

  4.LIMIT優化

    1) LIMIT對單表掃描的影響:如果索引掃描可用且花費低於全表掃描,則用索引掃描實現LIMIT(LIMIT取出很少量的行,否則優化器更傾向於使用全表掃描)

    2) LIMIT對排序的影響:如果LIMIT和ORDER BY子句協同使用,當取到LIMIT設定個數的有序元組數后,后續的排序操作將不再進行。

    3) LIMIT對去重的影響:如果LIMIT和DISTINCT子句協同使用,當取到LIMIT設定個數的唯一元組數后,后續的去重操作將不再進行。

    4) LIMIT受分組的影響:如果LIMIT和GROUP BY子句協同使用,GROUP BY按索引有序計算每個組的總數的過程中,LIMIT操作不必計數直到下一個分組開始。

    5) LIMIT 0:直接返回空結果集。

    6) MYSQL支持對不帶HAVING的子句進行優化。

  5.常見的一些優化規則

    1) 在索引鍵上執行排序操作,通常利用索引的有序性按序讀取數據而不進行排序。

    2) 選擇率低於10%時,利用索引的效果通常比讀取表數據的效果好。

    3) 當表的數據量較少時,全表掃描可能優於其它方式(如索引)。

 

八、物理查詢優化

  1.什么是物理查詢優化

    邏輯查詢優化:解決的是如何找出SQL語句等價的變換形式,使得SQL執行更高效。

    物理查詢優化解決的問題:

      1) 從可選的單表掃描方式中,挑選什么樣的單表掃描方式是最優的。

      2) 兩個表做連接時,如何連接最優。

      3) 多個表連接,連接順序有多重組合,哪種連接順序是最優的。

      4) 多個表連接,連接順序有多種組合,是否要對每種組合都探索?如果不全部探索,怎么找到最優的一種組合。

    物理查詢優化把邏輯查詢執行計划變為物理操作符,供執行器執行。

  2.物理查詢優化技術

    1) 代價估算模型:物理查詢優化的核心

      公式:總代價 = I/O代價 (數據讀取) + CPU代價 (數據計算處理)

      MySQL的代價估算模型: 總代價 = I/O代價 + CPU代價 + Memory代價 + Remote代價

      COST = pages * a_page_cpu_time + W * T;

      pages:計划運行時訪問的頁面數; a_page_cpu_time:每個頁面讀取的時間花費; pages * a_page_cpu_time 的乘積反映了I/O花費。

      T:訪問的元組數,反映了CPU花費(存儲層是以頁面為單位,數據以頁面的形式被讀入內存,每個頁面上可能有多條元組,訪問元組需要解析元組結構,才能把元組上的字段讀出,這消耗的是CPU)。如果是索引掃描,則還會包括索引讀取的花費。

      W:權重因子,表明I/O到CPU的相關性,又稱選擇率。選擇率用於表示在關系R中,滿足條件“A <operation> col” 的元組數與R的所有元組數N的比值。

    2) 單表掃描

      單表掃描是完成表連接的基礎。

      單表掃描算法:

        應用原則:盡量少獲取元組,用什么取什么,不要把所有的(行或列)都取出來。

        1) 順序掃描:從物理存儲上按照存儲順序直接讀取表的數據;當無索引可利用,或訪問表中的大部分數據,或表的數據量很小,使用順序掃描效果較好。

        2) 索引掃描:根據索引鍵讀索引,找出物理元組的位置;根據從索引中找到的位置,從存儲讀取數據頁面;索引掃描可以將元組按排序的順序返回;索引掃描有選擇率(低於10%)存在,讀數據花費的I/O會顯著減少;如果選擇率很高的話,不適宜使用索引掃描。

        3) 只讀索引掃描:根據索引鍵讀索引,索引中的數據能夠滿足條件判斷,不需要讀取數據頁面;比索引掃描少了讀取數據的I/O花費

        4) 行掃描:用於直接定位表中的某一行。對於元組,通常為元組增加特殊的列,可以通過特殊的列計算出元組的物理位置,然后直接讀取元組對應的頁面,獲取元組。

    3) 兩表連接

      兩表連接算法:

        1) 嵌套循環連接算法:適用於左右連接、內連接、半連接等等。

        2) 歸並(排序)連接算法:步奏:為兩個表創建可用內存緩沖區數為M的M個子表,每個子表排好序;然后讀入每個子表的第一塊到M個塊中,找出其中最小的先進行兩個表的元組的匹配,找出次小的匹配,...;依次完成其它子表的兩表連接。

        3) Hash連接算法:用連接列作為Hash的關鍵字,對內表進行Hash運算建立Hash表,然后對外表的每個元組的連接列用Hash函數求值,值映射到內表建立好的Hash表就可以連接了;否則,探索外表的下一個元組。

    4) 多表連接

      多表連接要解決的問題:

        1) 多表連接的順序:表的不同的連接順序,會產生許多不同的連接路徑;不同的連接路徑有着不同的效率。

        2) 多表連接的搜索空間:因為多表連接的順序不同,產生的連接組合會有多種,如果這個組合的數目巨大,連接次數會達到一個很高的數量級,最大可能的連接次數時N!(N的階乘)。所有的連接可能構成一個巨大的“搜索空間”。如何減小搜索空間,在一個可接受的時間范圍內,高效地生成查詢執行計划將成為一個難點。

 

九、MySql索引的優化、利用

  1.索引的優點:

    提高少量數據的獲取/檢索速度。(比如獲取某個用戶)

  2.索引的缺點:

    1) 占用存儲空間

    2) 多個索引耗費索引的挑選時間

    3) 降低寫操作的性能,需要實時維護索引

    4) 並發情況下索引的維護高度復雜

  3.什么時候不使用索引

    1) 數據的重復度高,即 選擇率高。

    2) 選擇率高於10%,不建議使用索引。

    3) 表的數據量較少,全表的掃描速度可能快於索引掃描。

  4.數據庫選擇索引的原則

    1) 代價估算模型計算代價,選擇小代價的方式

    2) 啟發式規則排除或強制選擇某類索引。

  5.MySQL支持的索引

    1)B-Tree:PRIMARY KEY、UNIQUE、INDEX、FULL TEXT(全文索引)

    2)Hash:MEMORY Tables(內存表)

      支持B-Tree的引擎:InnoDB、MyISAM、MEMORY/HEAP、NDB

      支持Hash的引擎:MEMORY/HEAP、NDB  

      B-Tree和Hash索引支持的操作符:=、<=>、IN()、IS NULL、IS NOT NULL ;

      B-Tree支持的索引:>、<、>=、<=、BETWEEN...AND...、!=、<>、LIKE(LIKE 表達式前不能有通配符,"xxx%") ;

  6.索引使用例子

    1)Like索引的利用情況:為了更好的利用索引,前面最好不要有通配符。

      

      

    

    2) MySQL優化器對<>、!=操作的優化

      MySQL對於=操作符可以利用索引。

      但是使用<>、!=時,MySQL認為取出的數據量大,即選擇率高,所以放棄了使用索引,看第二張圖。

      

      

      

    3) 對>、<操作符的影響

      總的來說就是,如果操作符的選擇率過高,則會放棄使用索引,而使用全表掃描,這種情況使用索引反而減慢了速度。

      

    4) 索引列有表達式計算,MySQL無法對表達式進行轉化,則索引不可用;所以不要在索引列上使用表達式。

      

    5) 其它

      a) 如果兩個長度不一樣,不會使用索引:char(10) = varchar(10) != char(8) != varchar(6)

      b) 查看索引使用的情況:SHOW STATUS LIKE "HANDLER_READ%";

        handler_read_key的值高:索引查詢多,查詢效率越高;

        handler_read_rnd_next的值高:隨機查詢多,查詢效率越低。

 

!!!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM