在日常工作中, 我們會記錄一些執行時間比較久的SQL語句, 找出這些SQL語句並不意味着完事了, 我們常常用到explain這個命令來查看一個這些SQL語句的執行計划, 查看該SQL語句有沒有使用上了索引, 有沒有做全表掃描, 所以我們需要深入了解MySQL基於開銷的優化器.
explain select * from t_member where member_id = 1;
在執行explain命令之后, 顯示的信息一共有12列, 分別是:
- id: 選擇標識符
- select_type: 查詢類型
- table: 輸出結果集的表
- partitions: 匹配的分區
- type: 表的連接類型
- possible_keys: 查詢時可能使用的索引
- key: 實際使用的索引
- key_len: 索引字段的長度
- ref: 列與索引的比較
- rows: 掃描出的行數
- filtered: 按表條件過濾的行百分比
- extra: 執行情況描述和說明
1. id
select標識符, 可以理解為SQL執行的順序, 從大到小執行.
id相同時執行順序從上到下, 在所有組中, id值越大, 優先級越高, 越先執行
2. select_type
查詢中每個select子句的類型.
- simple: 簡單的select, 不適用union或子查詢等. 例如:
SELECT * from t_member where member_id = 1;
- primary: 子查詢中最外層查詢, 查詢中若包含任何復雜的子部分, 最外層的select被標記為primary. 例如:
SELECT member_id from t_member where member_id = 3 UNION all SELECT member_id from t_member
- union: union中的第二個或后面的select語句. 例如:
SELECT member_id from t_member where member_id = 3 UNION all SELECT member_id from t_member
- dependent union: union中第二個或后面的select, 取決於外層的查詢. 例如
SELECT tm.* from t_member as tm where member_id in (SELECT member_id from t_member where member_id = 3 UNION all SELECT member_id from t_member)
- union result: union的結果集
- subquery: 子查詢中的第一個select. 例如:
SELECT * from t_member where member_id = (SELECT member_id from t_member where member_id = 5)
- dependent subquery: 子查詢中的第一個select, 取決於外面的select. 例如:
SELECT tm.* from t_member as tm where member_id in (SELECT member_id from t_member where member_id = 3 UNION all SELECT member_id from t_member)
- derived: 派生表的select(from子句的子查詢). 例如:
SELECT * from (SELECT * from t_member where member_id = 1) tbl
3. table
顯示這一步所訪問數據庫中表名稱. 有時候不是真實的表明, 可能是簡稱.
4. partitions
官方定義為The matching partitions(匹配的分區),該字段看table所在的分區, 值為NULL表示表未被分區.
5. type
對表訪問方式, 表示MySQL在表中找到所需行的方式, 又稱“訪問類型”. 常用的類型有: all、index、range、 ref、eq_ref、const、system(從左到右, 性能從差到好), 一般來說, 需要保證查詢至少達到range級別, 最好能達到ref級別.
- all: Full Table Scan, 全表掃描.
- index: Full Index Scan, 全索引掃描. index與all區別為index只遍歷索引樹, 通常比all快, 因為索引文件通常比數據文件小.
- range: 只檢索給定范圍的行, 使用一個索引來檢索行, 可以在key列中查看使用的索引, 一般出現在where條件中, 比如使用between,
<
,>
, in等查詢. 這種索引的范圍掃描比全表掃描要好, 因為索引的開始點和結束點都固定, 不用掃描全索引. - ref: 非唯一性索引掃描, 返回匹配某個單獨值的所有行. 本質上也是一種索引訪問, 返回匹配某值(某條件)的多行數據, 屬於查找和掃描的混合體.
- eq_ref: 類似ref, 區別在於使用的索引是唯一索引, 對於每個索引鍵值, 表中只有一條記錄匹配, 常見於主鍵或唯一索引掃描.
- const、system: 表示通過一次索引就找到了結果, 常見於primary key或unique索引, 因為只匹配一行數據, 所以查詢非常快. 如將主鍵置於where列表中, MySQL就能將該查詢轉換為一個常量. system是const類型的特例, 當查詢的表只有一行的情況下, 使用system.
6. possible_keys
顯示可能應用在表中的索引, 可能一個或多個. 查詢涉及到的字段若存在索引, 則該索引將被列出, 但不一定被查詢實際使用.
7. key
實際中使用的索引, 如為NULL, 則表示未使用索引. 要想強制MySQL使用或忽視possible_keys列中的索引, 在查詢中使用FORCE INDEX、USE INDEX或者IGNORE INDEX.
8. key_len
表示索引中所使用的字節數, 可通過該列計算查詢中使用的索引長度. 在不損失精確性的情況下, 長度越短越好. key_len顯示的值為索引字段的最大可能長度, 並非實際使用長度, 即key_len是根據表定義計算而得, 並不是通過表內檢索出的.
9. ref
顯示關聯的字段. 如果使用常數等值查詢, 則顯示const, 如果是連接查詢, 則會顯示關聯的字段.
10. rows
根據表統計信息及索引選用情況大致估算出找到所需記錄所要讀取的行數. 當然該值越小越好.
11. filtered
百分比值, 表示存儲引擎返回的數據經過濾后, 剩下多少滿足查詢條件記錄數量的比例.
12. extra
顯示十分重要的額外信息. 其取值有以下幾個:
- using filesort: 表明mysql會對數據使用一個外部的索引排序, 而不是按照表內的索引順序進行讀取. 在mysql中, 無法利用索引完成的排序操作稱為"文件排序". 當出現using filesort時就非常危險了, 在數據量非常大的時候幾乎"九死一生". 出現using filesort盡快優化sql語句.
- using temporary: 使用了臨時表保存中間結果, 常見於排序order by和分組查詢group by. 非常危險, “十死無生”, 急需優化.
- using index: 表明相應的select操作中使用了覆蓋索引, 避免訪問表的額外數據行, 效率不錯. 如果同時出現了using where, 表明索引被用來執行索引鍵值的查找. 如果沒有同時出現using where, 表明索引用來讀取數據而非執行查找動作.
- using where: 不用讀取表中所有信息, 僅通過索引就可以獲取所需數據, 這發生在對表的全部的請求列都是同一個索引的部分的時候, 表示mysql服務器將在存儲引擎檢索行后再進行過濾.
總結
explain包含的信息十分的豐富, 主要關注以下幾個字段信息.
- id: select子句或表執行順序, id相同, 從上到下執行, id不同, id值越大, 執行優先級越高.
- type: type主要取值及其表示sql的好壞程度(由好到差排序):system
>
const>
eq_ref>
ref>
range>
index>
ALL. 保證range, 最好到ref. - key: 實際被使用的索引列.
- ref: 關聯的字段, 常量等值查詢, 顯示為const, 如果為連接查詢, 顯示關聯的字段.
- Extra: 額外信息, 使用優先級using index
>
using filesort>
using temporary.