[MySQL]查詢的性能優化分析(二):Explain

MySQL Query Optimizer

MySQL Query Optimizer是MySQL中專門負責優化SELECT語句的模塊,其主要功能是:通過計算分析系統中收集到的統計信息,爲客戶端請求的Query提供MySQL認爲最優的執行計劃1

優化器執行過程:

  1. 客戶端向MySQL發起Query請求;
  2. 命令解析器模塊完成請求分類,區別出SELECT並轉發給MySQL Query Optimizer(查詢優化器);
  3. 查詢優化器對整條Query進行優化,處理掉一些常量表達式的預算,直接換算成常量值;
  4. 查詢優化器對Query中的查詢條件進行簡化和轉換,如去掉一些無用或顯而易見的條件、結構調整等;
  5. 分析Query中是否有Hint消息,是否可以通過Hint信息完全確定該Query的執行計劃;
  6. 若沒有Hint信息或不足以完全確定執行計劃,則會讀取所涉及對象的統計信息,根據Query進行寫相應的計算分析,得出最後的執行計劃。

查看執行計劃:Explain

Explain的作用

使用EXPLAIN關鍵字可以通過模擬優化器執行SQL查詢語句瞭解MySQL是如何處理SQL語句,從而分析查詢語句或是表結構中的性能瓶頸。
使用Explain可以瞭解到:

  • 表的讀取順序:通過執行計劃中的id判斷
  • 數據讀取操作的操作類型:通過執行計劃中的select_type判斷
  • 哪些索引可以使用:通過執行計劃中的possible_keys判斷
  • 哪些索引被實際使用:通過執行計劃中的key判斷
  • 表之間的引用:通過執行計劃中的ref判斷
  • 每張表有多少行被優化器查詢:通過執行計劃中的rows判斷

Explain的使用

基本語法:Explain + SQL語句2
執行計劃結果

圖1 執行計劃結果

執行計劃包含的信息:

  • id:select查詢的序列號,包含一組數字,表示查詢中執行select子句或操作表的順序
    • id相同:執行順序由上而下
      id相同,從上至下依次執行
    • id不同:如果是子查詢,id的序號會遞增,id值越大,優先級越高,越先被執行
      id不同,按id值從大到小依次執行
    • id相同、不同同時存在:相同的id視爲一組,組內從上往下順序執行,在所有id組中,id值越大,優先級越高,越先被執行
      id值相同、不同同時存在,按id值分組執行
  • select_type:操作類型
    • SIMPLE:不包含子查詢或者UNION的簡單查詢
    • PRIMARY:包含任何子查詢的查詢中最外層查詢(即最後加載的查詢)
    • SUBQUERY:在SELECT子句或者WHERE子句中的子查詢
    • DERIVED3:FROM子句中的子查詢(若包含UNION,則外層查詢將被標記爲DERIVED)
      DERIVED
    • UNION:UNION後的查詢
    • UNION RESULT:UNION連接的查詢合併後的結果集
      UNION和UNION RESULT
  • table:數據查詢基於的數據表
  • patitions:分區表命中的分區情況,非分區表該字段爲Null
  • type:訪問類型,常見的類型從好到壞的順序是system>const>eq_ref>ref>range>index>ALL,一般來說,保證查詢至少能夠達到range級別,最好能達到ref級別
    • ALL:全表掃描,百萬級別以上數據量的需要優化;
    • index:全索引掃描,掃描只會遍歷索引樹,相較於ALL從硬盤中讀取全表數據,index掃描是從索引中讀取全表數據,由於索引文件通常比數據文件小,使得index掃描比ALL掃描快;
      index
    • range:索引範圍掃描,返回索引在給定範圍的匹配行;
      range
    • ref:非唯一性索引掃描,多表聯結查詢匹配某個單獨值的結果可能爲多個匹配行;
    • eq_ref:唯一性索引掃描,多表聯結查詢匹配某個單獨值的結果只有一個匹配行4,通常是將主鍵或唯一索引與聯結的前表中的列進行比較;
      eq_ref
    • const:唯一性索引掃描,單表查詢結果最多隻有一個匹配行,通常是將primary key或unique索引的所有部分與常量值進行比較;
      const
    • system:表只有一行記錄(等於系統表),這是const類型的特里,可以忽略不考慮。
  • possible_keys:顯示可能應用在表查詢中的所有索引,即查詢涉及到的字段上若存在索引,則該索引將被列出,但不一定被實際使用
  • key:實際使用的索引,如果爲NULL,則沒有創建索引,或者創建了索引但未使用
  • key_len:表示索引中使用的字節數,可以通過該列計算查詢中使用的索引的長度,即索引字段的最大可能長度,並非實際使用長度。在不損失精確性的情況下,長度越短越好。
  • ref:表示被用於與索引比較的常量或列
  • rows:表示根據表統計信息及索引選用情況,大致估算出檢索所需要讀取的行數,行數越少越好
  • filtered:存儲引擎返回的數據在server層過濾後,剩下滿足查詢的記錄數量的比例(%)
  • extra:表示包含不適合在其他列中顯示但十分重要的信息
    • using filesort:表示查詢和排序的字段與索引不符(引用的字段個數和順序不符),MySQL無法利用索引完成排序操作,會影響查詢的性能,儘量優化消除。如下圖,索引爲empno,而排序字段爲sal,此時索引的排序功能不再起作用;
      using filesort
    • Using temporary:表示MySQL在對查詢結果排序時使用保存了中間結果的臨時表,常見於order by和group by,會嚴重影響查詢的性能;
    • Using Index:表示相應的查詢操作中使用了覆蓋索引5,避免訪問了表的數據行
      • 存在using where:表明索引被用來執行索引鍵值的查找
        Using index和Using where
      • 不存在using where:表明索引用來讀取數據而非執行查找動作
        Using index
    • Using where:表示使用了where過濾
    • Using index condition:表示相應的查詢操作中同時使用創建了索引的列和未創建索引的列,5.6版本後加入的新特性
      • 存在Using where:表示未創建索引的列出現在WHERE子句中(emp表中對deptno、comm、sal三列創建了複合索引)
        Using index condition和Using where
      • 不存在Using where:表示未創建索引的列出現在SELECT子句中(emp表中對deptno、comm、sal三列創建了複合索引)
        Using index condition
    • Using join buffer:表示使用了聯結緩存,join聯結使用的比較多,建議增大緩存
    • Impossible where:WHERE子句的值總是false,不能獲取到任何數據結果

  1. MySQL認爲最優的數據檢索方式,不意味着就是DBA認爲的最優的數據檢索方式,這部分認知的差異往往容易耗費時間。 ↩︎

  2. 本文中使用的數據表是Oracle自帶的scott用戶的數據表的MySQL副本,所以不另外提供建表語句 ↩︎

  3. MySQL會遞歸執行這部分查詢,並把結果放在臨時表裏,即使這樣會增加服務器負擔。 ↩︎

  4. 官網原文:One row is read from this table for each combination of rows from the previous tables. ↩︎

  5. 覆蓋索引(Covering Index):查詢的數據列只需要從索引中就可以獲取,不需要讀取數據行,即一個索引包含了滿足查詢結果的數據列 ↩︎

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章