關於sql優化,這個話題太大,我怕我說很差,所以本文僅以sql優化工具爲題,若是對sql優化有興趣,我建議去閱讀下高性能Mysql這本書,我最近也在讀,此文也算是我在閱讀此書過程當中的一些收穫總結。
對於大部分開發人員來講,日常接觸的無非就是增刪改查這些基本操做,建立存儲過程,視圖等等都是DBA該乾的活,可是想要把這些基本操做寫的近乎完美也是一件難事。
而explain顯示了MySQL如何使用索引來處理select語句以及鏈接表。能夠經過模擬mysql的優化器幫助選擇更好的索引和寫出更優化的查詢語句。
首先,咱們來明確下explain能幹嗎 ?mysql
- 表的讀取順序
- 數據讀取操做的操做類型
- 哪些索引可使用
- 哪些索引被實際使用
- 表之間的引用
- 每張表有多少行被優化器查詢
說了這麼多使用explain的好處,那麼實際上到底該怎麼玩? 答案: explain + 待執行的sql 
explain使用.pngsql
從上表中咱們看到,經過explain+sql執行後,顯示了一張列表,那麼接下來咱們就詳細說說這個個列表中表頭各個字段的意思,只有先明確了各個字段的意思,才能知道sql 的優虐程度!
- id:決定表的讀取順序
執行select 語句查詢的序列號,包含一組數字,表示查詢中執行select子句或操做表的順序
它有三種狀況:
1.id相同,執行順序由上至下;
2.id不一樣,若是是子查詢,id的序號會遞增,id值越大優先級越高,越先被執行;
3.id相同不一樣,同時存在,若是id相同,能夠認爲是一組,從上往下順序執行,在全部組中,id值越大,優先級越高,越先執行;
- select_type:查詢的類型,也就是數據讀取操做的操做類型,他一共有如下5種:
simple:簡單的select查詢,查詢中不包含子查詢或者union;
primary:查詢中若包含任何複雜的子查詢,最外層查詢則被標記;
subquery:在select或者where列表中包含了子查詢;
derived:在from列表中包含的子查詢被標記爲DERIVED(衍生表),mysql會遞歸執行這些子查詢,把結果放臨時表中;
union:若第二個select出如今union以後,則被標記爲union,若union包含在from子句的子查詢中,外層select將被標記爲:DERIVED;
union result:從union表(即union合併的結果集)中獲取select查詢的結果;
- type:訪問類型排列
顯示查詢使用了何種類型,從最好到最差依次是:system > const > eq_ref > ref > range > index > all
system:表只有一行記錄(等於系統表),這是const類型的特例,平時不會出現,這個也可忽略不計;
const:表示經過索引一次就找到了,const用於比較primary key或者unique索引。由於只匹配一行記錄,因此很快. 若是將主鍵置於where列表中,mysql就能將該查詢轉換成一個常量;
eq_ref:惟一性索引掃描,對於每個索引鍵,表中只有一條記錄與之匹配,經常使用於主鍵或惟一索引掃描;
ref:非惟一性索引掃描,返回匹配某個單獨值得全部行,本質上也是一種索引訪問,它返回全部匹配某個單獨值的行,然而,它可能會找到多個符合條件的行,因此它應該屬於查找和掃描的混合體;
range:只檢索給定範圍的行,使用一個索引來選擇行,key列顯示使用哪一個索引,通常就是在你的where語句中出現了between,<,>,in等的查詢;這種範圍索引掃描比全表掃描要好,由於它只須要開始於索引的某一個點,結束於另外一個點,不用掃描所有索引;
index:index於all區別爲index類型只遍歷索引樹,這一般比all快,由於索引文件一般比數據文件小;也就是說雖然all和index都是讀寫表,但index是從索引中讀取的,而all是從硬盤中讀的;
all:也就是全表掃描;
- 備註:通常來講,得保證查詢至少達到range級別,最好能達到ref.
- possible_keys:顯示可能會被應用到這張表的索引,一個或者多個;查詢涉及到的字段上若存在索引,則該索引將被列出,但不必定被查詢實際使用到;
- key:實際使用到的索引.若是爲null,則沒有使用索引;查詢中若使用了覆蓋索引,則該索引僅出如今key列表中;
- key_len:表示索引中使用的字節數,可經過該列計算查詢中使用的索引的長度,在不損失精確性的狀況下,長度越短越好; key_len顯示的值爲索引字段的最大可能長度,並不是實際使用長度,即key_len是根據表定義計算而得,不是經過表內檢索出的;
- ref:顯示索引的哪一列被使用了,若是可能的話,是一個常數,哪些列或常量別用於查找索引列上的值;
- rows:根據表統計信息及索引選用狀況,大體估算出找到所需的記錄所須要讀取的行數;
-
Extra:包含不適合在其它列中顯示但十分重要的額外信息:
1.using filesort(出現這個東西很差):說明mysql會對數據使用一個外部的索引排序,而不是按照表內的索引順序進行讀取,mysql中沒法利用索引完成的排序操做稱爲"文件排序";數據庫

優化案例1.png緩存
2.using temporary(出現這個東西更很差,使用到了臨時表):使用了臨時表保存中間結果,Mysql在對查詢結果排序時使用臨時表,常見於排序order by和分組查詢group by.工具

優化案例2.png性能
3.using index:表示相應的select操做中使用了覆蓋索引(Covering Index),避免了訪問了表的數據行,效率不錯! 
Paste_Image.png優化
若是同時出現using where ,代表索引被用來執行索引鍵值的查找; 
Paste_Image.pngspa
若是沒有同時出現using where,代表索引用來讀取數據而非執行查找操做;排序
覆蓋索引:理解方式一:就是select的數據列只用從索引列中就能取得,沒必要讀取數據行,Mysql能夠利用索引返回select列表中的字段,而沒必要根據索引再次讀取數據文件,換句話說查詢列要被所建的索引列覆蓋;理解方式二:索引是高效找到行的一個方法,可是通常數據庫也能使用索引找到一個列的數據,所以它沒必要讀取整個行,畢竟索引的葉子節點存儲了索引數據;當能經過讀取索引就能夠獲得想要的數據,那就不須要讀取行了;一個索引包含了(或者覆蓋了)知足查詢結果的數據就叫作覆蓋索引。
注意:若是要使用覆蓋索引,必定要注意select列表中只取出須要的列,不可select *;由於若是將全部的字段一塊兒作索引會致使索引文件過大,查詢性能降低;遞歸
- using where:使用了where
- using join buffer:使用了連接緩存;
- impossible where:where 子句的值老是false,不能用來獲取任何元素;
- select tables optimized away:在沒有group by子句的狀況下,基於索引優化MIN/MAX操做或者對於MyISAM存儲引擎優化count(*)操做,沒必要等到執行階段再進行計算,查詢執行計劃生成的階段即完成優化;
- distinct