轉載地址:https://juejin.im/post/5d141528e51d4577565367d0
MySQL中的explain命令顯示了mysql如何使用索引來處理select語句以及連接表。explain顯示的信息可以幫助選擇更好的索引和寫出更優化的查詢語句。
一、格式
explain + select 語句;
例如:explain select * from tb_student;
二、5.5和5.7版本explain的區別
5.7之后的版本默認會有 partitions 和 filtered兩列,但是5.5版本中是沒有的,需要
使用explain partitions select ……來顯示帶有partitions 的列,
使用explain extended select ……來顯示帶有filtered的列。
本文是基於5.5.54版本的。
三、explain的作用
1.描述MySQL如何執行查詢操作、執行順序,使用到的索引,以及MySQL成功返回結果集需要執行的行數。
2.可以幫助我們分析 select 語句,讓我們知道查詢效率低下的原因,從而改進我們的查詢,讓查詢優化器能夠更好的工作
查詢優化器的作用:
1.優化select 語句,分析哪些是常量表達式(例如id=1),以及分析哪些表達式可以直接轉換成常量的
2.對where條件進行簡化和轉換,如去掉無用條件,調整條件結構等
3.讀取涉及的表的統計信息,並計算分析(例如返回的行數,索引信息等),最終得出執行計划
四、執行計划(QEP)包含的信息

- id:標識符,表示執行順序
- select _type:查詢類型
- table:輸出行所引用的表
- partitions:使用的哪個分區,需要結合表分區才可以看到
- type:表示按某種類型來查詢,例如按照索引類型查找,按照范圍查找。從最好到最差的連接類型為const、eq_reg、ref、range、indexhe和all
- possible_keys:可能用到的索引,保存的是索引名稱,如果是多個索引的話,用逗號隔開
- key:實際用到的索引,保存的是索引名稱,如果是多個索引的話,用逗號隔開
- key_len:表示本次查詢中,所選擇的索引長度有多少字節
- ref:顯示索引的哪一列被使用了,如果可能的話,是一個常數
- rows:顯示mysql認為執行查詢時必須要返回的行數
- filtered:通過過濾條件之后對比總數的百分比
- extra:額外的信息,例如:using file sort ,using where, using join buffer,using index等
五、執行計划中各個參數的詳解
1.id
表示select標識符,同時表明執行順序,也就是說id是一個查詢的序列號,查詢序號即為sql語句執行的順序。
(1)當id值相同時,按從上到下的順序執行
(2)當id全部不同時,按id從大到小執行
(3)當id部分不同時,先執行id大的,id相同的,按從上到下的順序執行
2.select_type
(1)simple:表示簡單的select,沒有union和子查詢
(2)primary:最外面的查詢 或者 主查詢,在有子查詢的語句中,最外面的select查詢就是primary
(3)subquery:子查詢
(4)union:union語句的第二個或者說是后面那一個select
(5)union result:union之后的結果
(6)dependent unoin:unoin 中的第二個或隨后的 select 查詢,依賴於外部查詢的結果集
(7)dependent subquery:子查詢中的第一個 select 查詢,依賴於外部 查詢的結果集
(8)derived:衍生表(5.7版本中不存在這一個)
3.table
通常是表名,或者表的別名,或者一個為查詢產生臨時表的標示符(如派生表、子查詢、集合)
4.partitions
使用的哪些分區(對於非分區表值為null),在5.5版本中需要加上explain partitions select .....
5.type
(1)const:表中最多有一個匹配行,const用於比較primary key 或者unique索引。因為只匹配一行數據,所以很快
(2)eq_ref:唯一性索引掃描,對於每個來自於前面的表的記錄,從該表中讀取唯一一行
(3)ref:非唯一性索引掃描,對於每個來自於前面的表的記錄,所有匹配的行從這張表取出
(4)ref_or_null:類似於ref,但是可以搜索包含null值的行,例如:select * from student where address='xxx' or address is null,需要在address建立索引。
(5)index_merge:查詢語句用到了一張表的多個索引時,mysql會將多個索引合並到一起
(6)range:按指定范圍(如in、<、>、between and等,但是前提是此字段要建立索引)來檢索,很常見。如:select * from student where id < 5,id上要有索引。
(7)index:全”表“掃描,但是是在索引樹中掃描,通常比ALL快,因為索引文件通常比數據文件小,index掃描是通過二叉樹的方式掃描,而all是掃描物理表。(也就是說雖然all和index都是讀全表,但index是從索引中讀取的,而all是從硬盤中讀的)。例如:select name from student,但name字段上需要建立索引,也就是查詢的字段屬於索引中的字段。
(8)all:全表掃描,掃描完整的物理表,此時就需要優化了。
6.possible_keys
指出 MySQL 能在該表中可能使用的索引,顯示的是索引的名稱,多個索引用逗號隔開,如果沒有,則為null。
7.key
MySQL決定實際用到的索引,顯示的是索引的名稱,多個索引用逗號隔開,如果沒有,則為null
8.key_len
當用到組合索引的時候判斷索引是否完全用上。
實例:假設student表中有id int,name char(20) DEFAULT NULL,address varchar(20) DEFAULT NULL,remark varchar(20) NOT NULL 字段,建立的索引是 idx_address_remark(在address和remark上建立的組合索引)
查詢的sql是:select * from student where address='深圳' and remark='java coder',此時,執行計划中的key_len是 (203+1+2)+ (203+2)= 125,那么這個是怎么得來的呢?
解析:20表示建表的時候 varchar(20) ,3表示utf8字符集占用3個字節,1表示MySQL需要1個字節表示null,2表示變長字段(varchar是變長的)。
假設drop掉剛剛建立的索引,新建索引 idx_name_address(在name和address上建立組合索引)
查詢的sql是:select * from student where name='xbq' and address='深圳',此時,執行計划中的key_len是 (203+1)+ (203+2)= 123,那么這個值是怎么得來的呢?
解析:20表示建表的時候 char(20) ,3表示utf8字符集占用3個字節,1表示MySQL需要1個字節標識null,即 20*3+1,后面的同樣的道理。
key_len只計算where條件用到的索引長度,而排序和分組就算用到了索引,也不會計算到key_len中。
計算key_len的公式:
varchr(10)變長字段且允許NULL = 10 * ( character set:utf8=3,gbk=2,latin1=1) + 1(NULL) + 2(變長字段)
varchr(10)變長字段且不允許NULL = 10 *( character set:utf8=3,gbk=2,latin1=1) + 2(變長字段)
char(10)固定字段且允許NULL = 10 * ( character set:utf8=3,gbk=2,latin1=1)+1(NULL)
char(10)固定字段且不允許NULL = 10 * ( character set:utf8=3,gbk=2,latin1=1)
9.ref
顯示索引的哪一列被使用了,如果可能的話,是一個常數
10.rows
顯示mysql認為執行查詢時必須要返回的行數,可結合type和key分析,沒有用上索引的情況下,會全表掃描。rows的值越小越好,說明檢索的數據少
11.filtered
給出了一個百分比的值,這個百分比值和rows列的值一起使用,可以估計出那些將要和執行計划中的前一個表(前一個表就是指id列的值比當前表的id小的表)進行連接的行的數目。
這一列在5.5版本中,需要加上 explain extended select ....。
12.extra
此字段顯示一些額外的信息,但是此字段的部分值具有優化的參考意義。
(1)using where:表示查詢使用了where 語句來處理結果
(2)using index:表示使用了覆蓋索引。這個值重點強調了只需要使用索引就可以滿足查詢表的要求,不需要直接訪問表數據。
(3)using join buffer:這個值強調了在獲取連接條件時沒有使用索引,並且需要連接緩沖區來存儲中間結果。如果出現了這個值,那應該注意,根據查詢的具體情況可能需要添加索引來改進性能
(4)using filesort:這是 order by 語句的結果。這可能是一個CPU密集型的過程。using filesort表示出現了文件內排序,表示很不好的現象,必須要優化,特別是大表,可以通過選擇合適的索引來改進性能,用索引來為查詢結果排序。
(5)using temporary:mysql需要創建一張臨時表來保存中間結果。 也就是說,需要先把數據放到臨時表中,然后從臨時表中獲取需要的數據。出現這種臨時表,也是必須需要優化的地方,特別是數據量大的情況。兩個常見的原因是在來自不同表的列上使用了distinct,或者使用了不同的 order by 和 group by 列。
作者:碼咖
鏈接:https://juejin.im/post/5d141528e51d4577565367d0
來源:掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。