1. 程式人生 > >explain解析

explain解析

MySQL執行計劃呼叫方式
執行計劃包含的資訊
執行計劃顯示內容解讀
MySQL執行計劃的侷限
MySQL5.6支援OPTIMIZER_TRACE

1.什麼是歸併排序
將已有序的子序列合併,得到完全有序的序列

2.執行計劃中Using temporaryusing filesort的區別?
Using temporary
表示MySQL需要使用臨時表來儲存結果集,常見於排序和分組查詢
這個值表示使用了內部臨時(基於記憶體的)表。一個查詢可能用到多個臨時表。有很多原因都會導致MySQL在執行查詢期間建立臨時表。
兩個常見的原因是在來自不同表的上使用了DISTINCT,或者使用了不同的ORDER BY和GROUP BY列。可以強制指定一個臨時表使用基於
磁碟的MyISAM儲存引擎。這樣做的原因主要有兩個:
1)內部臨時表佔用的空間超過min(tmp_table_size,max_heap_table_size)系統變數的限制
2)使用了TEXT/BLOB 列
using filesort


MySQL中無法利用索引完成的排序操作稱為“檔案排序”--filesort演算法,有可能在記憶體排序,也可能利用磁碟

Using where; Using temporary; Using filesort:表示進行關聯查詢時(mysql中關聯查詢的概念要更寬泛,不僅僅指兩張表的關聯才叫關聯查詢),
使用了臨時表,並在生成臨時表後,又進行了檔案排序;
Using where; Using temporary表示,僅僅生成了臨時表,而沒有進行檔案排序(在生成臨時表的時候已經排序完畢了)。

filesort:跟file沒有關係,只是sort,如果無法使用index進行排序時,資料庫會額外的進行資料排序
需要注意的是:由於 Using filesort是使用演算法在 記憶體中進行排序,MySQL對於排序的記錄的大小也是有做限制:max_length_for_sort_data,預設為1024
show variables like '%max_length_for_sort_data%';
如果排序查詢的資料兩大於這個預設值的話,還是會使用Using filesort,當排序查詢的資料量在預設值的範圍內是,在排序的欄位上加上索引可以提升MySQL查詢的速度
where u.id=100 order by u.update_time
idx_user_id_update_time(id,update_time)
磁碟臨時表和檔案排序


記憶體臨時表,myisam磁碟臨時表

3.表中只有一條資料,為什麼在執行計劃中也會有using filesort?(實驗測試)
([email protected]:3306) [test]> explain select * from t22 where id=1 order by name;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-----------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-----------------------------+
| 1 | SIMPLE | t22 | NULL | ALL | NULL | NULL | NULL | NULL | 1 | 100.00 | Using where; Using filesort |

覆蓋索引(Covering Index)
MySQL可以利用索引返回select列表中的欄位,而不必根據索引再次讀取資料檔案
包含所有滿足查詢需要的資料的索引稱為 覆蓋索引(Covering Index)
注意:
如果要使用覆蓋索引,一定要注意select列表中只取出需要的列,不可select *,因為如果將所有欄位一起
做索引會導致索引檔案過大,查詢效能下降
Using where
表示MySQL伺服器在儲存引擎受到記錄後進行“後過濾”(Post-filter),
如果查詢未能使用索引,Using where的作用只是提醒我們MySQL將用where子句來過濾結果集

MySQL執行計劃的侷限
EXPLAIN不會告訴你關於觸發器、儲存過程的資訊或使用者自定義函式對查詢的影響情況
? EXPLAIN不考慮各種Cache
? EXPLAIN不能顯示MySQL在執行查詢時所作的優化工作
? 部分統計資訊是估算的,並非精確值(如:對Innodb行數的估算)
? EXPALIN只能解釋SELECT操作,其他操作要重寫為SELECT後檢視執行計劃(5.6.*版本已經可以對
update,delete操作做EXPALIN)

MySQL5.6支援OPTIMIZER_TRACE

Explain 詳解
使用一個示例 SQL 來解釋 explain :
select id from r_ibeacon_biz_device_d where ftime >= 20151126 and ftime <= 20151126 and biz_id = 11602 limit 50;
IDX_BID_FTIME<biz_id, ftime>是表r_ibeacon_biz_device_d的其中一條索引。
Biz_id,ftime 均為 bigint 型別。
我們著重關注幾個重點欄位的重點值:
- type: 索引的使用方式
eq_ref … 索引,關聯匹配若干行 ,最多隻會有一條匹配結果,一般是通過主鍵或唯一鍵索引來訪問
ref … 索引(字首)匹配 ,JOIN語句中驅動表索引引用的查詢
ref_or_null 與ref的唯一區別就是在使用索引引用的查詢之外再增加一個空值的查詢
index_merge 查詢中同時使用兩個(或更多)索引,然後對索引結果進行合併(merge),再讀取表資料。這種連線型別意味著使用了Index Merge優化方法
range … 索引範圍掃(BETWEEN、IN、>=、LIKE)得到資料
index … 索引全掃描
unique_subquery 子查詢中的返回結果欄位組合是主鍵或唯一約束
index_subquery 子查詢中的返回結果欄位組合是一個索引(或索引組合),但不是一個主鍵或唯一索引。
all … 表全掃描
示例中使用的索引是使用全索引範圍掃描,所以 type 為 range
- possible_keys:適用查詢的索引列表。示例中有三條索引適用本次查詢。
- key: 查詢實際執行使用的索引。示例使用的為 IDX_BID_FTIME
- key_len:查詢使用索引的長度。
null 1位元組
tinyint 1位元組
int 4位元組
bigint 8位元組
double 8位元組
datetime 8位元組
timestamp 4位元組
varchr(10)變長欄位且允許NULL: 10*(Character
Set:utf8=3,gbk=2,latin1=1)+1(NULL)+2(變長欄位)
char(10)固定欄位且允許NULL: 10*(Character
Set:utf8=3,gbk=2,latin1=11(NULL)

以上是常用型別的長度,示例中key_len為 18,即:8 位元組 (biz_id bigint)+1 位元組 ( biz_id 允許為 null )
+8 位元組 ( ftimebigint )+1 位元組 ( ftime 允許為 null )。所以本次查詢是使用了索引的所有欄位加速查詢

- rows:查詢預估掃描的行數

常見問題彙總結
- Range 怎麼使用索引?
詳見上文
- Order by使用索引嗎?
該問題可以由以下資料解釋:
SQL queries with an order by clause don’t need to sort the result explicitly if the relevant index already delivers the
rows in the required order. That means the same index that is used for the where clause must also cover the order by clause.
總之一句話:索引本身並不能避免排序,當根據索引取出的資料已經滿足 order by 子句的要求就可以避免排序操作。
- order by太慢?
避免資料排序,採用索引排序 (分頁查詢文藝寫法)
`- limit offset太慢?
避免大 offset,使用 where 語句過濾更多的行。
- 為什麼不走索引(索引也走了,還是慢)?
型別是否一致: int vs char(varchar)、varchar(32)vs varchar(64)
字符集是否一致:涉及表關聯時,兩表字符集是否一致。