1. 引言
在實際開發中,我們用於捕捉性能問題最常用的就是打開
慢查詢,定位執行效率差的SQL
,那麼當我們定位到一個SQL以後還不算完事,我們還需要知道該SQL的執行計劃,比如是全表掃描,還是索引掃描,這些都需要通過EXPLAIN去完成
。EXPLAIN命令是查看優化器如何決定執行查詢的主要方法。可以幫助我們深入瞭解MySQL的基於開銷的優化器,還可以獲得很多可能被優化器考慮到的訪問策略的細節,以及當運行SQL語句時哪種策略預計會被優化器採用
。需要注意的是,生成的QEP並不確定,它可能會根據很多因素髮生改變。MySQL不會將一個QEP(Query Execution Plan)和某個給定查詢綁定,QEP將由SQL語句每次執行時的實際情況確定,即便使用存儲過程也是如此。儘管在存儲過程中SQL語句都是預先解析過的,但QEP仍然會在每次調用存儲過程的時候才被確定。
2. 使用
explain select .....
explain insert .....
explain update .....
explatin delete .....
explain主要用來分析執行查詢相關的計劃
3. 查詢計劃分析
explain select * from t_emp;
id關鍵字
id作用
:包含一組數字,表示查詢中執行select子句或操作表的順序
- id相同,執行順序由上至下
- 如果是子查詢,id的序號會遞增,id值越大優先級越高,越先被執行
- id如果相同,可以認爲是一組,從上往下順序執行;在所有組中,id值越大,優先級越高,越先執行
id相同
爲一組,順序執行
explain select * from t_dept,t_emp;
id不同
如果是子查詢,id的序號會遞增,id值越大優先級越高,越先被執行
explain select * from t_emp where id = (select id from t_emp where id ='100001');
id相同和不同
**id如果相同,可以認爲是一組,從上往下順序執行;在所有組中,id值越大,優先級越高,越先執行 **
explain select * from t_emp where id = (select e.id from (select d.id from t_dept d where d.name='教學部') s,t_emp e where s.id =e.deptid);
select_type關鍵字
select_type
查看類型查詢的類型,主要是用於區分普通查詢、聯合查詢、子查詢等複雜的查詢
SIMPLE:
簡單的select查詢,查詢中不包含子查詢或者unionPRIMARY:
查詢中包含任何複雜的子部分,最外層查詢則被標記爲primarySUBQUERY:
在select 或 where列表中包含了子查詢DERIVED:
在from列表中包含的子查詢被標記爲derived(衍生),mysql或遞歸執行這些子查詢,把結果放在零時表裏UNION:
若第二個select出現在union之後,則被標記爲union;若union包含在from子句的子查詢中,外層select將被標記爲derivedUNION RESULT:
從union表獲取結果的select
type關鍵字
type
訪問類型, sql查詢優化中一個很重要的指標,結果值從好到壞依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
一般來說,好的sql查詢至少達到range級別,最好能達到ref
system:表只有一行記錄(等於系統表),這是const類型的特例,平時不會出現,可以忽略不計
const:表示通過索引一次就找到了,const用於比較primary key 或者 unique索引。因爲只需匹配一行數據,所有很快。如果將主鍵置於where列表中,mysql就能將該查詢轉換爲一個const
explain select * from t_emp where id='1';
- eq_ref:唯一性索引掃描,對於每個索引鍵,表中只有一條記錄與之匹配。常見於主鍵 或 唯一索引掃描。
explain select * from t_dept d,t_emp e where d.id = e.id;
- ref:非唯一性索引掃描,返回匹配某個單獨值的所有行。本質是也是一種索引訪問,它返回所有匹配某個單獨值的行,然而他可能會找到多個符合條件的行,所以它應該屬於查找和掃描的混合體
explain select * from t_dept d,t_emp e where d.id = e.deptid;
- range:只檢索給定範圍的行,使用一個索引來選擇行。key列顯示使用了那個索引。一般就是在where語句中出現了bettween、<、>、in等的查詢。這種索引列上的範圍掃描比全索引掃描要好。只需要開始於某個點,結束於另一個點,不用掃描全部索引
explain select * from t_emp where id ='1' or id ='2';
- index:Full Index Scan,index與ALL區別爲index類型只遍歷索引樹。這通常爲ALL塊,應爲索引文件通常比數據文件小。(Index與ALL雖然都是讀全表,但index是從索引中讀取,而ALL是從硬盤讀取)
explain select id from t_emp;
- ALL:Full Table Scan,遍歷全表以找到匹配的行
possible_keys
查詢涉及到的字段上存在索引,則該索引將被列出,但不一定被查詢實際使用
create index name_index on t_emp(name);
explain select * from t_emp where name='xxx';
explain select * from t_emp where age=23;
explain select * from t_emp where age=23 and name='xxx';
key
實際使用的索引,如果爲NULL,則沒有使用索引。
查詢所有自動組合查詢字段的順序以便利用索引
show index from t_emp;
key_len
表示索引中使用的字節數,查詢中使用的索引的長度(最大可能長度),並非實際使用長度,理論上長度越短越好。key_len是根據表定義計算而得的,不是通過表內檢索出的
ref
顯示
索引的那一列是否被使用了
,如果使用,是一個常量const。
rows
根據表統計信息及索引選用情況,大致估算出找到所需的記錄所需要讀取的行數
explain select name from t_emp ;
Extra
Using index:
表示相應的select操作中使用了覆蓋索引(Covering Index),避免了訪問表的數據行,效率高 如果同時出現Using where,表明索引被用來執行索引鍵值的查找
(參考上圖)
如果沒用同時出現Using where,表明索引用來讀取數據而非執行查找動作