MySQL優化-explain執行計劃詳解

MySQL Query Optimizer簡介

  • MySQL中有專門負責優化SELECT語句的優化器模塊, 主要功能 : 通過計算分析系統中收集到的統計信息, 爲客戶端請求的Query提供它認爲最優的執行計劃
  • 當客戶端向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等命令來查看系統性能狀態
  • 程序中SQL語句問題, Explain查看執行計劃

上面的三個問題一般會有對應的運維人員去處理, 作爲開發人員最需要關注的是SQL問題

覆蓋索引(Covering Index), 又稱爲索引覆蓋

這個概念下面需要用到,先放在這裏

  • 理解方式一 : 就是SELECT的數據列只用從索引中就能夠取到, 不必讀取數據行, MySQL可以利用索引返回SELECT列表中的字段, 而不必根據索引再次讀取數據文件, 換句話說, 查詢列要被所建的索引覆蓋。
  • 理解方式二 : 索引是高效找到行的一個方法, 但是一般數據庫也能使用索引找到一個列的數據, 因此它不必讀取整個行。畢竟索引的葉子節點存儲了它們索引的數據; 當能通過讀取索引就可以得到想要的數據, 那就不需要讀取行了。一個索引包含了(或覆蓋了)滿足查詢結果的數據就叫做覆蓋索引

注意 :

如果要使用覆蓋索引, 一定要注意SELECT列表中只取出需要的列, 不能SELECT *, 因爲如果將所有字段一起做索引會導致索引文件過大, 查詢性能下降。

執行計劃(Explain)詳解

簡介

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

Explain能得到哪些信息

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

使用方法

  • explain + SQL語句

執行計劃包含的信息:

執行計劃包含的信息

執行計劃信息詳解

id

select查詢的序列號, 包含一組數字, 表示查詢中執行select子句或操作表的順序

  • id相同 : 執行順序由上向下
    1538179519523

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

  • ID相同不同, 同時存在 : id如果相同.可以認爲是一組, 從上往下順序執行; 在所有組中, id值越大, 優先級越高, 越先執行
    在這裏插入圖片描述

    derived表示衍生, 第一行中的derived2表示, 這個虛表是由id爲2的語句所衍生的

select_type

查詢的類別, 主要用於區別普通查詢, 聯合查詢, 子查詢等複雜查詢

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

table

顯示這一行的數據是關於哪張表的

type

訪問類型, 顯示查詢使用了何種類型, 從最好到最差依次是 :

system>const>eq_ref>ref>range>index>ALL

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

  • system : 表只有一行記錄(等於系統表), 這是const類型的特例, 平時不會出現

  • const : 表示通過索引依次就找到了, const用於比較primary key或者unique索引。因爲只匹配一行數據, 索引很快, 如將主鍵置於where列表中, MySQL就能將該查詢轉換爲一個常量
    1538181867346

  • eq_ref : 唯一性索引掃描, 對於每個索引鍵, 表中只有一條記錄與之匹配。常見於主鍵或唯一索引掃描
    在這裏插入圖片描述

  • ref : 非唯一性索引掃描, 返回匹配某個單獨值的所有行。本質上也是一種索引訪問, 它返回所有匹配某個單獨值的行, 可能會找到多個符合條件的行, 所以這個應該屬於查找和掃描的混合體
    在這裏插入圖片描述

  • range : 只檢索給定範圍的行, 使用一個索引來選擇行。key列顯示使用了哪個索引, 一般就是在where語句中出現了between, < ,> ,in等的查詢。這種範圍索引掃描比全表掃描要好, 因爲它只需要開始於索引的某一點, 而結束於另一點, 不用掃描全部索引。
    在這裏插入圖片描述

  • index : Full Index Scan, index與ALL的區別爲index類型只遍歷索引樹。這通常比ALL快, 因爲索引文件通常比數據文件小。(也就是說雖然ALL和Index都是讀全表, 但index是從索引中讀取的, 而all是從硬盤中讀取的)

    1538182606816

  • ALL : Full Table Scan(全表掃描), 將遍歷全表以找到匹配的行
    1538182703359

possible_keys, key

possible_keys :

顯示可能應用在這張表中的索引, 一個或多個。

查詢涉及到的字段是若存在索引, 則該索引將被列出, 但不一定被查詢實際使用

key :

實際使用的索引, 如果爲NULL, 則沒有使用索引。

查詢中若使用了覆蓋索引, 則該索引僅出現在key列表中
覆蓋索引演示 :
1538183425081
possible_keys,key演示 :
1538183026993

key_len

  • 表示索引中使用的字節數, 可通過該列計算查詢中使用的索引的長度。在不損失精確性的情況下, 長度越短越好。
  • key_len顯示的值爲索引字段的最大可能長度, 並非實際使用長度, 即key_len是根據表定義計算而得, 不是通過表內檢索獲得的

ref

顯示索引的哪一列被使用了, 如果可能的話, 最好是一個常數。哪些列或常量被用於查找索引列上的值
1538220546536

rows

根據表統計信息及索引選用情況, 大致估算出找到所需記錄所需要讀取的行數

Extra

包含不適合在其他列中顯示但十分重要的額外信息

  • Using filesort : 說明MySQL會對數據使用一個外部的索引排序, 而不是按照表內索引順序進行讀取。MySQL中無法利用索引完成的排序操作稱爲"文件排序"。
    在這裏插入圖片描述

  • Using temporary : 使用了臨時表保存中間結果, MySQL在對查詢結果排序時使用了臨時表。常見於排序order by和分組查詢group by。
    在這裏插入圖片描述

  • Using index : 表示相應的SELECT操作中使用了覆蓋索引(Covering Index), 避免了訪問表的數據行, 效率還可以

    如果同時出現Using where, 表明索引被用來執行索引鍵值的查找;

    如果沒有出現同時出現Using where, 表明索引用來讀取數據而非執行查找動作
    在這裏插入圖片描述

  • Using where : 使用了where過濾

  • Using join buffer : 使用了連接緩存

  • Impossible WHERE : where子句值總是false, 不能用來獲取任何數據, 如name=‘張三’ and name=‘李四’

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

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

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