背景mysql
一般咱們在經過SQL慢查詢日誌或其它三方工具分析出查詢性能較差的SQL語句後,常常須要定位緣由。那麼對於MYSQL咱們經常使用其內置的執行計劃(EXPLAIN)命令對慢的語句進行模擬執行查詢過程的分析,從而發現咱們語句的性能瓶頸點,再進行有針對性地優化工做。sql
執行計劃
緩存
1、爲何要分析執行計劃細節 ,咱們能獲得哪些方面信息 ?ide
理解語句執行的任務拆分和任務的執行順序;
工具
分析執行計劃拆分的任務內部的劃分和含義;性能
分析單步執行任務的執行效果的理想程度;優化
瞭解語句的執行計劃建議可使用哪些索引;spa
查看執行計劃究竟內部用上了哪些目前的索引;3d
追蹤執行過程當中,對錶及字段的引用邏輯;日誌
瞭解每一個子任務過濾的表記錄數,從而調整表的鏈接和組織方式;
2、語法
EXPLAIN +SQL語句 , 如:EXPLAIN select * from table;
詳解分析結果
1、任務id理解
場景1. 執行任務id同樣,代表查詢優化器執行任務的順序是至上而下順序執行。
以下圖查詢語句,執行將從表t1開始,依次執行t3和t2的任務。
EXPLAIN SELECT t2.* FROM t1,t2,t3 WHERE t1.id=t2.id AND t1.id=t3.id AND t1.other_column='';
場景2. 執行任務id不一樣, 查詢優化器執行規則爲:id值最大的任務優先被執行,按由大到小的順序依次執行拆分的任務項。
以下圖語句中執行過程:執行將從任務3開始,依次執行任務2和任務1;
EXPLAIN SELECT t2.* FROM t2 WHERE id=(
SELECT id FROM t1 WHERE id=(SELECT t3.id FROM t3 WHERE t3.other_column='')
);
場景3. 執行任務id相同與不一樣混合場景,查詢優化器優先執行任務id最大的;任務id同樣的部分單獨分組,至上而下順序執行。
以下圖語句中執行過程: 任務將被優先執行,而後再從上到下依次執行id=1d的兩個任務;
EXPLAIN
SELECT t2.* FROM( SELECT t3.idFROM t3 WHERE t3.other_column='' ) s1,t2 WHERE s1.id=t2.id ;
2、任務查詢類型 - select_type
從語句總體上,劃分爲多種不一樣的查詢類型場景。
類型 |
描述 |
SIMPLE |
簡單的select查詢,不包含子查詢和UNION |
PRIMARY |
查詢中若包含複雜的子部分,最外層查詢則被標記爲PRIMARY |
SUBQUERY |
在SELECT或WHERE列表中包含子查詢 |
DERIVED |
在FROM列表中包含的子查詢被標記爲DERVIED(衍生)MYSQL會遞歸執行這些子查詢,把結果放在臨時表裏面 |
UNION |
若第二個SELECT出如今UNION以後,則被標記爲UNION; 若UNION包含在FROM子句的子查詢中,外層SELECT被標記爲DERIVED |
UNION RESULT |
從UNION表獲取結果的SELECT |
1.SIMPLE類型,如:EXPLAIN SELECT * FROM t_order;
2. PRIMARY和SUBQUERY類型
如:EXPLAIN SELECT *,(SELECT id FROM t_order_detail WHERE order_id=2) FROM t_order t1;
3. DERIVDE 衍生類型
如:EXPLAIN SELECT t1.* FROM t1,( SELECT t2.* FROM t2 WHERE t2.id =1) s2 WHERE t1.id=s2.id;
截圖中的<derivde2>中"2"表明從t2實體表,衍生出的虛擬表
4. UNION / UNION RESULT類型
如如下語句: EXPLAIN SELECT * FROM t1 UNION SELECT * FROM t2;
3、建議可使用哪些索引 - possible_keys
EXPLAIN
SELECT t1.orderno,t1.created_time,t2.goods_id,t2.id AS detailid
FROM t_order t1 INNER JOIN t_order_detail t2 ON t1.id = t2.order_id
WHERE t1.created_time >= '2020-07-18' AND t1.created_time <= '2020-07-20' ;
如上截圖待優化語句中,紅框中的索引,就是查詢優化器建議使用的索引進行對應的優化
4、實際使用到的索引 - key
以下圖中,就是查詢優化器實際用到的索引(多是多個)
CREATE INDEX idx_col1_col2 ON t1 (col1, col2);
EXPLAIN SELECT col1,col2 FROM t1 ;
5、分析是否充分用到了索引 - key_len
影響key_len值的因素:字符集設置、索引字段的長度(或字節數)、索引字段是否設置容許爲null。
字符集和 char / varchar類型字節對應關係
字符集 |
單箇中文佔字節空間 |
單個英文佔字空間 |
utf-8 |
3 |
1 |
gbk |
2 |
1 |
場景1、對於char類型
單個字段key_len長度計算公式爲 = 字符集佔用最大字節空間 * 字段長度 + 是/否容許爲null (是=1, 否=0) ;
因此截圖1中的key_len=30的計算=3*10+0=30;
場景2、對於varchar類型
單個字段key_len長度計算公式爲 = 字符集佔用最大字節空間 * 字段長度+(預留長度) + 是/否容許爲null (是=1, 否=0) ;
公式中的預留長度值: mysql官網的介紹是: 長度在1 ~ 255之間,預留長度=1; 長度在256 ~ 16384之間,預留長度=2;
因此截圖2中的key_len=32的計算=3*10+2+0=32;
場景3、數字類型 (包括:int系列, 單精度、雙精度、Decimal等)
單個字段key_len長度計算公式爲 = 字段類型佔字節空間 + 是/否容許爲null (是=1, 否=0) ;
截圖3中的key_len=4的計算=4+0=4;
截圖4中的key_len=2的計算=1+1=2;
場景4、日期/日期時間/時間戳/時間等類型, 計算規則同場景三(這裏再也不贅述)。
其它須知原則
充分用到索引的key_len長度確定比未充分用到的要長,但字段加索引的原則是優先選擇長度較短的數據類型上加索引,查詢更高效;
複合索引key_len原則:複合索引有最左前綴的特性,若是複合索引能所有使用上,則是複合key_len爲各索引字段的key_len長度之和,這也能夠用來斷定複合索引是否部分使用,仍是所有使用;
附數據類型佔字節空間對應表
數據類型 |
所佔空間 |
最大值 |
INT |
4字節 |
10位長度.21億多 |
BIGINT |
8字節 |
19位長 |
SMALLINT |
2字節 |
-32768~32767 |
TINYINT |
1字節 |
-128~127 |
FLOAT |
4字節 |
|
DOUBLE |
8字節 |
|
DECIMAL |
每4個字節存9個數字,小數點佔1個字節 |
|
CHAR |
255個字符 |
|
VARCHAR |
0~65535字節 |
16384個字符 |
TEXT |
16K |
|
MEDUIMTEXT |
16M |
|
LONGTEXT |
4G |
|
DATETIME |
5.5及如下爲8字節; 5.6以上版本爲5字節 |
1000~9999(YEAR) |
DATE |
3字節 |
1000~9999(YEAR) |
TIME |
3字節 |
|
TIMESTAMP |
4字節 |
1970~2038 |
6、任務訪問類型 - type
訪問類型值,從最好到最壞依次排序級別是:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
級別值詳解
system: 優化器拆分的計劃id對應表中只有一條記錄
const: 經過索引一次就找到了目標數據
eq_ref: 惟一索引掃描,表中惟一記錄與之匹配,經常使用在主鍵或惟一索引
如執行包含主鍵id的索引查詢type即爲eq_ref級:EXPLAIN SELECT * from t1,t2 where t1.id=t2.id
ref: 非惟一索引掃描
如執行非惟一索引查詢type即爲ref級: EXPLAIN select count(DISTINCTcol1) from t1 where col1='ac'
range: 檢索給定範圍的行,使用一個索引來選擇行; (經常使用在bewteen and 、IN、<>);
index : 計劃執行的是全表掃描( 經過索引掃描全表, select出的字段全是索引列) ;
ALL: 同上全表掃描,但掃描的是全表數據;
需掌握級別:system > const > eq_ref > ref
range > index > ALL
通常查詢須要保證達到range 級別,至少爲ref
7、對錶和列的引用 - ref
8、引用表多少行被優化器查詢到 - row
9、十分重要的額外信息 - extra
Extra值 |
描述 |
Using filesort |
說明mysql會對數據使用一個外部的索引(因爲不按索引排序規則排列查詢條件致使),而不是用表內索引順序進行讀取數據。這種沒法利用索引完成數據排序的狀況成爲文件排序 |
Using temporary |
使用了臨時表保存中間結果,mysql對查詢結果排序時使用臨時表。常在ORDER BY 或GROUP BY中出現 |
Using index |
是否使用了覆蓋索引 |
Using where |
代表使用where進行了字段過濾 |
Using join buffer |
代表使用了鏈接緩存 |
Impossible where |
代表where子句的值老是false, 不能用來獲取任何元組 |
1. 產生filesort文件排序的緣由
建立複合索引時的字段排序順序是key(a,b,c); 可是採用where或order by 時,卻只按照c或其它字段排序,這樣查詢優化器就沒法採用索引來排序,需從新創建排序規則,即產生了這種狀況;
以下截圖所示:
解決辦法:order by c2,c3 ;
2. temporary表產生的緣由
在order by或group by排序 中不採用索引字段排序順序,致使產生中間臨時表。
解決辦法:group by c1,c2 ;
3.索引覆蓋舉例
4. join buffer理解:不循環數據逐一和另外一張表匹配,而是緩存整個小表數據,總體和另外一張表進行匹配方式,提高查詢效率;
5. impossible_where: 沒法查詢到任何數據
總結
以上就是MYSQL執行計劃模擬執行結果的全部細節分析。有任何關於這方面的問題,能夠在下方留言,你們一塊兒討論。下次咱們將給你們分享SQL高級查詢優化的諸多幹貨,請繼續關注!