MySQL性能優化(四)-- MySQL explain詳解


轉載地址: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)包含的信息

 

img

 

  1. id:標識符,表示執行順序
  2. select _type:查詢類型
  3. table:輸出行所引用的表
  4. partitions:使用的哪個分區,需要結合表分區才可以看到
  5. type:表示按某種類型來查詢,例如按照索引類型查找,按照范圍查找。從最好到最差的連接類型為const、eq_reg、ref、range、indexhe和all
  6. possible_keys:可能用到的索引,保存的是索引名稱,如果是多個索引的話,用逗號隔開
  7. key:實際用到的索引,保存的是索引名稱,如果是多個索引的話,用逗號隔開
  8. key_len:表示本次查詢中,所選擇的索引長度有多少字節
  9. ref:顯示索引的哪一列被使用了,如果可能的話,是一個常數
  10. rows:顯示mysql認為執行查詢時必須要返回的行數
  11. filtered:通過過濾條件之后對比總數的百分比
  12. 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
來源:掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM