1. 程式人生 > >MySql-sql語句效能分析

MySql-sql語句效能分析

MySql Query Optimizer

        1 Mysql中有專門負責優化SELECT語句的優化器模組,主要功能:通過計算分析系統中收集到的統計資訊,為客戶端請求的Query提供他認為最優的執行計劃(他認為最優的資料檢索方式,但不見得是DBA認為是最優的,這部分最耗費時間)
        2 當客戶端向MySQL 請求一條Query,命令解析器模組完成請求分類,區別出是 SELECT 並轉發給MySQL Query Optimizer時,MySQL Query Optimizer 首先會對整條Query進行優化,處理掉一些常量表達式的預算,直接換算成常量值。並對 Query 中的查詢條件進行簡化和轉換,如去掉一些無用或顯而易見的條件、結構調整等。然後分析 Query 中的 Hint 資訊(如果有),看顯示Hint資訊是否可以完全確定該Query 的執行計劃。如果沒有 Hint 或Hint 資訊還不足以完全確定執行計劃,則會讀取所涉及物件的統計資訊,根據 Query 進行寫相應的計算分析,然後再得出最後的執行計劃。

MySQL常見瓶頸

        CPU:CPU在飽和的時候一般發生在資料裝入記憶體或從磁碟上讀取資料時候
        IO:磁碟I/O瓶頸發生在裝入資料遠大於記憶體容量的時候
        伺服器:伺服器硬體的效能瓶頸:top,free, iostat和vmstat來檢視系統的效能狀態

Explain檢視執行計劃

        使用EXPLAIN關鍵字可以模擬優化器執行SQL查詢語句,從而知道MySQL是如何處理你的SQL語句的。分析你的查詢語句或是表結構的效能瓶頸

1、能幹嘛

        表的讀取順序
        資料讀取操作的操作型別
        哪些索引可以使用
        哪些索引被實際使用
        表之間的引用
        每張表有多少行被優化器查詢

2、用法:Explain + SQL語句

3、執行計劃包含的資訊

     

4、各欄位解釋(id、type、key、rows、Extra是衡量指標)

    (1) id:select查詢的序列號,包含一組數字,表示查詢中執行select子句或操作表的順序
        三種情況
              id相同,執行順序由上至下

                     
              id不同,如果是子查詢,id的序號會遞增,id值越大優先順序越高,越先被執行

                       
              id相同不同,同時存在:id如果相同,可以認為是一組,從上往下順序執行;在所有組中,id值越大,優先順序越高,越先執行,下圖中<derived2>表示衍生表s1表,derived2的2代表id=2

                        

    (2) select_type:查詢的型別,主要是用於區別普通查詢、聯合查詢、子查詢等的複雜查詢

            

    SIMPLE:簡單的 select 查詢,查詢中不包含子查
    PRIMARY:查詢中若包含任何複雜的子部分,最外層查詢則被標記為
    SUBQUERY:在SELECT或WHERE列表中包含了子查詢
    DERIVED:在FROM列表中包含的子查詢被標記為DERIVED(衍生),MySQL會遞迴執行這些子查詢, 把結果放在臨時表裡
    UNION:若第二個SELECT出現在UNION之後,則被標記為UNION;若UNION包含在FROM子句的子查詢中,外層SELECT將被標記為:DERIVED
    UNION RESULT:從UNION表獲取結果的SELECT

    (3) table:顯示這一行的資料是關於哪張表的

    (4) type:訪問型別排列,顯示查詢使用了何種型別,結果值從最好到最壞依次是:

   system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL 
   
   system:表只有一行記錄(等於系統表),這是const型別的特列,平時不會出現,這個也可以忽略不計
   const:表示通過索引一次就找到了,const用於比較primary key或者unique索引。因為只匹配一行資料,
          所以很快如將主鍵置於where列表中,MySQL就能將該查詢轉換為一個常量
   eq_ref:唯一性索引掃描,對於每個索引鍵,表中只有一條記錄與之匹配。常見於主鍵或唯一索引掃描
   ref:非唯一性索引掃描,返回匹配某個單獨值的所有行.本質上也是一種索引訪問,它返回所有匹配某個
        單獨值的行,然而,它可能會找到多個符合條件的行,所以他應該屬於查詢和掃描的混合體
   range:只檢索給定範圍的行,使用一個索引來選擇行。key 列顯示使用了哪個索引一般就是在你的where語
          句中出現了between、<、>、in等的查詢這種範圍掃描索引掃描比全表掃描要好,因為它只需要開
          始於索引的某一點,而結束語另一點,不用掃描全部索引。
   index:Full Index Scan,index與ALL區別為index型別只遍歷索引樹。這通常比ALL快,因為索引檔案通
          常比資料檔案小。(也就是說雖然all和Index都是讀全表,但index是從索引中讀取的,而all是從
          硬碟中讀的)
   all:Full Table Scan,將遍歷全表以找到匹配的行

         一般來說,得保證查詢至少達到range級別,最好能達到ref。

         const: where id = 1   id是寫死的常量id只有一條 效能好

                

         eq_ref: where t1.id = t2.id  t2.id只有一條記錄  t2表中只有一條記錄 t2是全表掃描

               

         ref:  where col1 = 'ac'   ac是常量,但是col1是非唯一性索引,找到非唯一性索引的全部行

               

        rang: 

                

                 

        index:

                 

        all: where條件欄位沒建立索引,或者索引失效

                

   (5) possible_keys : 顯示可能應用在這張表中的索引,一個或多個。查詢涉及到的欄位上若存在索引,則該索引將被列出,但不一定被查詢實際使用

   (6) key : 實際使用的索引。如果為NULL,則沒有使用索引;

            查詢中若使用了覆蓋索引,則該索引僅出現在key列表中:select 查詢的欄位個數、順序和複合索引的欄位的個數、順序一一符合

            

   (7) key_len:表示索引中使用的位元組數,可通過該列計算查詢中使用的索引的長度。在不損失精確性的情況下,長度越短越好,key_len顯示的值為索引欄位的最大可能長度,並非實際使用長度,即key_len是根據表定義計算而得,不是通過表內檢索出的

             

   (8) ref:顯示索引的哪一列被使用了,如果可能的話,是一個常數。哪些列或常量被用於查詢索引列上的值

              由key_len可知t1表的idx_col1_col2被充分使用,col1匹配t2表的col1,col2匹配了一個常量,即 'ac'

              

   (9) rows:根據表統計資訊及索引選用情況,大致估算出找到所需的記錄所需要讀取的行數

             建立索引之前和建立索引之後,找出記錄所需要的行數對比

              

   (10) Extra:包含不適合在其他列中顯示但十分重要的額外資訊(前三個最重要:Using filesort、Using temporary表明語句爛需要優化,Using index表明語句還不錯)

            Using filesort :說明mysql會對資料使用一個外部的索引排序,而不是按照表內的索引順序進行讀取。
MySQL中無法利用索引完成的排序操作稱為“檔案排序”

                    索引順序是col1、col2、col3,where用到col1 ,order by用到col3但是,但是中間少了col2

                    

                    索引順序是col1、col2、col3,where用到col1 ,order by用到col2 、col3

                    

            Using temporary:使了用臨時表儲存中間結果,MySQL在對查詢結果排序時使用臨時表。常見於排序 order by 和分組查詢 group by。

                       索引順序是col1、col2,group by跨過col1用col2

                        

                       索引順序是col1、col2,group by按順序使用col1、col2 

                         

            Using index:表示相應的select操作中使用了覆蓋索引(Covering Index),避免訪問了表的資料行,效率不錯!如果同時出現using where,表明索引被用來執行索引鍵值的查詢;如果沒有同時出現using where,表明索引用來讀取資料而非執行查詢動作。

                        覆蓋索引(Covering Index):就是select的資料列只用從索引中就能夠取得,不必讀取資料行,MySQL可以利用索引返回select列表中的欄位,而不必根據索引再次讀取資料檔案,換句話說查詢列要被所建的索引覆蓋。

                        

           Using where:表明使用了where過濾

           Using join buffer:使用了連線快取:

           impossible where:where子句的值總是false,不能用來獲取任何元組   where name = '1' and name = '2'

                           

           select tables optimized away:在沒有GROUP BY子句的情況下,基於索引優化MIN/MAX操作或者對於MyISAM儲存引擎優化COUNT(*)操作,不必等到執行階段再進行計算,查詢執行計劃生成的階段即完成優化。

           distinct:優化distinct操作,在找到第一匹配的元組後即停止找同樣值的動作

           

 

例子:

第一行(執行順序4):id列為1,表示是union裡的第一個select,select_type列的primary表 示該查詢為外層查詢,table列被標記為<derived3>,表示查詢結果來自一個衍生表,其中derived3中3代表該查詢衍生自第三個select查詢,即id為3的select。【select d1.name......】


第二行(執行順序2):id為3,是整個查詢中第三個select的一部分。因查詢包含在from中,所以為derived。【select id,name from t1 where other_column=''】


第三行(執行順序3):select列表中的子查詢select_type為subquery,為整個查詢中的第二個select。【select id from t3】


第四行(執行順序1):select_type為union,說明第四個select是union裡的第二個select,最先執行【select name,id from t2】


第五行(執行順序5):代表從union的臨時表中讀取行的階段,table列的<union1,4>表示用第一個和第四個select的結果進行union操作。【兩個結果union操作】