sql優化是高級工程師必修課,對于百萬級以上的數據,要避免全表掃描,可以借助一些分析工具查看sql執行過程,進而優化sql
explain顯示了MySQL如何使用索引來處理select語句以及連接表。可以通過模擬mysql的優化器幫助選擇更好的索引和寫出更優化的查詢語句。
首先,我們來明確下explain能干嘛 ?
- 表的讀取順序
- 數據讀取操作的操作類型
- 哪些索引可以使用
- 哪些索引被實際使用
- 表之間的引用
- 每張表有多少行被優化器查詢
- 說了這么多使用explain的好處,那么實際上到底該怎么玩? 答案: explain + 待執行的sql
從上表中我們看到,通過explain+sql執行后,顯示了一張列表,那么接下來我們就詳細說說這個個列表中表頭各個字段的意思,只有先明確了各個字段的意思,才能知道sql 的優劣程度!
1. id:決定表的讀取順序
執行select 語句查詢的序列號,包含一組數字,表示查詢中執行select子句或操作表的順序
它有三種情況:
- id相同,執行順序由上至下;
- id不同,如果是子查詢,id的序號會遞增,id值越大優先級越高,越先被執行;
- id相同不同,同時存在,如果id相同,可以認為是一組,從上往下順序執行,在所有組中,id值越大,優先級越高,越先執行;
2. select_type:查詢的類型,也就是數據讀取操作的操作類型,他一共有以下5種:
1. simple:簡單的select查詢,查詢中不包含子查詢或者union;
2. primary/union:
- primary:查詢中最外層的SELECT(如兩表做UNION或者存在子查詢的外層的表操作為PRIMARY,內層的操作為UNION)
- union:union操作中,查詢中處于內層的select(內層的select語句與外層的select語句沒有依賴關系)
3. dependent union / union result:
- dependent union:union操作中,查詢中處于內層的select(內層的select語句與外層的select語句有依賴關系)
- union result:union 操作的結果,id值通常為null
4. subquery / dependent subquery:
- subquery:子查詢中首個select(如果有多個子查詢存在)
- dependent subquery:子查詢中首個SELECT,但依賴于外層的表(如果有多個子查詢存在)
5. derived/MATERIALIZED:
- derived:在from列表中包含的子查詢被標記為DERIVED(衍生表),mysql會遞歸執行這些子查詢,把結果放臨時表中;
- MATERIALIZED:被物化的子查詢
6. UNCACHEABLE SUBQUERY/UNCACHEABLE UNION:
- UNCACHEABLE SUBQUERY:對于外層的主表,子查詢不可被物化,每次都需要計算(耗時操作)
- UNCACHEABLE UNION:UNION操作中,內層的不可被物化的子查詢(類似于UNCACHEABLE SUBQUERY)
3. type:訪問類型排列
顯示查詢使用了何種類型,從最好到最差依次是:system > const > eq_ref > ref > range > index > all
explain 的type類型的理解
- 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.
4. possible_keys:顯示可能會被應用到這張表的索引,一個或者多個;查詢涉及到的字段上若存在索引,則該索引將被列出,但不一定被查詢實際使用到;
5. key:實際使用到的索引.如果為null,則沒有使用索引;查詢中若使用了覆蓋索引,則該索引僅出現在key列表中;
6. key_len:表示索引中使用的字節數,可通過該列計算查詢中使用的索引的長度,在不損失精確性的情況下,長度越短越好; key_len顯示的值為索引字段的最大可能長度,并非實際使用長度,即key_len是根據表定義計算而得,不是通過表內檢索出的;
7. ref:顯示索引的哪一列被使用了,如果可能的話,是一個常數,哪些列或常量別用于查找索引列上的值;
8. rows:根據表統計信息及索引選用情況,大致估算出找到所需的記錄所需要讀取的行數;
9. Extra:包含不適合在其它列中顯示但十分重要的額外信息:
using filesort(出現這個東西不好):說明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,不能用來獲取任何元素;
- select tables optimized away:在沒有group by子句的情況下,基于索引優化MIN/MAX操作或者對于MyISAM存儲引擎優化count(*)操作,不必等到執行階段再進行計算,查詢執行計劃生成的階段即完成優化;
- distinct :去掉重復的數據