SQL調(diào)優(yōu)之Explain關(guān)鍵字詳解
explain關(guān)鍵字可以模擬優(yōu)化器執(zhí)行 SQL 查詢語(yǔ)句,從而知道 MySQL 是如何處理 SQL 語(yǔ)句的。分析查詢語(yǔ)句或表結(jié)構(gòu)的性能瓶頸。執(zhí)行語(yǔ)句:explain + SQL語(yǔ)句。表頭信息如下:
explain各個(gè)字段代表的意思
- id :select查詢的序列號(hào),包含一組數(shù)字,表示查詢中執(zhí)行select子句或操作表的順序。
- select_type :查詢類型 或者是 其他操作類型。
- table :正在訪問(wèn)哪個(gè)表。
- partitions :匹配的分區(qū)。
- type :訪問(wèn)的類型。
- possible_keys :顯示可能應(yīng)用在這張表中的索引,一個(gè)或多個(gè),但不一定實(shí)際使用到。
- key :實(shí)際使用到的索引,如果為NULL,則沒(méi)有使用索引。
- key_len :表示索引中使用的字節(jié)數(shù),可通過(guò)該列計(jì)算查詢中使用的索引的長(zhǎng)度。
- ref :顯示索引的哪一列被使用了,如果可能的話,是一個(gè)常數(shù),哪些列或常量被用于查找索引列上的值。
- rows :根據(jù)表統(tǒng)計(jì)信息及索引選用情況,大致估算出找到所需的記錄所需讀取的行數(shù)。
- filtered :查詢的表行占表的百分比。
- Extra :包含不適合在其它列中顯示但十分重要的額外信息。
ID 字段
select 查詢的序列號(hào),包含一組數(shù)字,表示查詢中執(zhí)行 select 子句或操作表的順序。三種情況:
id 相同: 執(zhí)行順序由上而下:
explain select t2.* from t1,t2,t3 where t1.id = t2.id and t1.id = t3.id and t1.other_column = '';
id 不同: 如果是子查詢,id 序號(hào)會(huì)遞增,id 越大優(yōu)先級(jí)越高,越先被執(zhí)行。
explain select t2.* from t2 where id = (select id from t1 where id = (select t3.id from t3 where t3.other_column = ''));
id 相同不同同時(shí)存在: id 如果相同,可以認(rèn)為是一組,由上往下執(zhí)行;在所有組里 id 越大,優(yōu)先級(jí)越高,越先執(zhí)行。
explain select t2.* from (select t3.id from t3 where t3.other_column = '') s1,t2 where s1.id = t2.id;
select_type 字段
主要用于區(qū)別普通查詢、聯(lián)合查詢、子查詢等的復(fù)雜程度。
SIMPLE: 簡(jiǎn)單的 select 查詢,查詢中不包含子查詢或者 UNION。
PRIMARY: 查詢中若包含任何復(fù)雜的自查詢,最外層查詢?yōu)?PRIMARY。
SUBQUERY: 在 SELECT 或 WHERE 中包含子查詢。
UNCACHEABLE SUBQUERY:一個(gè)子查詢的結(jié)果不能被緩存,必須重新評(píng)估外鏈接的第一行。
DERIVED: 在 FROM 列表中包含的子查詢被標(biāo)記為 DERIVED(衍生)MySQL 會(huì)遞歸執(zhí)行這些子查詢,把結(jié)果放進(jìn)臨時(shí)表。
UNION: 若第二個(gè) SELECT 出現(xiàn)在 UNION 之后,則被標(biāo)記為 UNION,若 UNION 包含在 FROM 子句的子查詢,則外層SELECT 將被標(biāo)記為 DERIVED。
UNION RESULT: 從 UNION表中獲取結(jié)果的 SELECT。
table字段
顯示這行數(shù)據(jù)是關(guān)于那張表
type字段
首先說(shuō)一下這個(gè)字段,要記住以下10個(gè)狀態(tài),(從左往右,越靠左邊的越優(yōu)秀)
NULL > system > const > eq_ref > ref > ref_or_null > index_merge > range > index > ALL
NULL
MySQL能夠在優(yōu)化階段分解查詢語(yǔ)句,在執(zhí)行階段用不著再訪問(wèn)表或索引。存在這樣一種情況,大家都知道索引是將數(shù)據(jù)在B+Tree中進(jìn)行排序了,所以你的查詢速率才這么高,那么B+樹(shù)的最邊上的葉子節(jié)點(diǎn)是不是要么是最大值要么是最小值?。考热荒愣贾懒?,那MySQL比你更知道?。‘?dāng)你要查詢最大值或者最小值時(shí),MySQL會(huì)直接到你的索引得分葉子節(jié)點(diǎn)上直接拿,所以不用訪問(wèn)表或者索引。
NULL的前提是你已經(jīng)建立了索引。
SYSTEM
表只有一行記錄(等于系統(tǒng)表),這是const類型的特列,平時(shí)不大會(huì)出現(xiàn),可以忽略。
const
表示通過(guò)索引一次就能找到,const用于比較 primary和 unique索引。因?yàn)橹黄ヅ湟恍袛?shù)據(jù),所以很快。
簡(jiǎn)單來(lái)說(shuō),const是直接按主鍵或唯一鍵讀取。
eq_ref
用于聯(lián)表查詢的情況,按聯(lián)表的主鍵或唯一鍵聯(lián)合查詢。多表join時(shí),對(duì)于來(lái)自前面表的每一行,在當(dāng)前表中只能找到一行。這可能是除了system和const之外最好的類型。
ref 可以用于單表掃描或者連接。如果是連接的話,驅(qū)動(dòng)表的一條記錄能夠在被驅(qū)動(dòng)表中通過(guò)非唯一(主鍵)屬性所在索引中匹配多行數(shù)據(jù),或者是在單表查詢的時(shí)候通過(guò)非唯一(主鍵)屬性所在索引中查到一行數(shù)據(jù)。
ref_or_null 類似ref,但是可以搜索值為NULL的行。
index_merge
表示查詢使用了兩個(gè)以上的索引,最后取交集或者并集,常見(jiàn)and ,or的條件使用了不同的索引,官方排序這個(gè)在ref_or_null之后,但是實(shí)際上由于要讀取多個(gè)索引,性能可能大部分時(shí)間都不如range。
range
只檢索給定范圍的行,使用一個(gè)索引來(lái)選擇行。一般where語(yǔ)句中出現(xiàn)between、<、>、in等的查詢。這種范圍掃描索引比全表掃描要好,因?yàn)橹恍栝_(kāi)始索引的某一點(diǎn),而結(jié)束另一點(diǎn),不用掃描全部索引;
index
Full Index Scan,index與 ALL區(qū)別為 index類型只遍歷索引樹(shù),索引文件通常比數(shù)據(jù)文件小。index從索引中讀取,而All是從硬盤(pán)讀??;
ALL
從磁盤(pán)中讀??;如果一個(gè)查詢的type是All,并且表的數(shù)據(jù)量很大,那么請(qǐng)解決它!??!
possible_keys字段
這個(gè)表里面存在且可能會(huì)被使用的索引,可能會(huì)在這個(gè)字段下面出現(xiàn),但是一般都以key為準(zhǔn)。
key字段
實(shí)際使用的索引,如果為null,則沒(méi)有使用索引,否則會(huì)顯示你使用了哪些索引,查詢中若使用了覆蓋索引(查詢的列剛好是索引),則該索引僅出現(xiàn)在key列表。
ref字段
列與索引的比較,表示上述表的連接匹配條件,即哪些列或常量被用于查找索引列上的值。
rows字段和Filter字段
rows是根據(jù)表的統(tǒng)計(jì)信息和索引的選用情況,優(yōu)化器大概幫你估算出你執(zhí)行這行函數(shù)所需要查詢的行數(shù)。
Filter是查詢的行數(shù)與總行數(shù)的比值。其實(shí)作用與rows差不多,都是數(shù)值越小,效率越高。
Extra字段
Using index
表示相應(yīng)的 select操作中使用了覆蓋索引(convering index),避免訪問(wèn)了表的數(shù)據(jù)行,效率不錯(cuò)!
覆蓋索引(covering index ,或稱為索引覆蓋)即從非主鍵索引中就能查到的記錄,而不需要查詢主鍵索引中的記錄,避免了回表的產(chǎn)生減少了樹(shù)的搜索次數(shù),顯著提升性能。
Using temporary
表示MySQL需要使用臨時(shí)表來(lái)存儲(chǔ)結(jié)果集,常見(jiàn)于排序 order by和分組查詢 group by。
Using fileSort
表示當(dāng)SQL中有一個(gè)地方需要對(duì)一些數(shù)據(jù)進(jìn)行排序的時(shí)候,優(yōu)化器找不到能夠使用的索引,所以只能使用外部的索引排序。
MySQL無(wú)法利用索引完成的排序操作稱為“文件排序”。導(dǎo)致該問(wèn)題的原因一般是Where條件和order by子句作用在了不同的列上,一般可以通過(guò)合適的索引來(lái)減少或者避免。(出現(xiàn)表示不好)
上面提到的常見(jiàn)情況,SQL語(yǔ)句通常寫(xiě)成這樣select * from a where type = 5 order by id,這類語(yǔ)句一般會(huì)產(chǎn)生Using filesort這個(gè)選項(xiàng),即使你在type和id上分別添加了索引。我們想一下它的工作過(guò)程,先根據(jù)type的索引從所有數(shù)據(jù)信息中挑選出滿足type = 5條件的,然后根據(jù)id列的索引信息對(duì)挑選的數(shù)據(jù)進(jìn)行排序,所以產(chǎn)生了Using filesort選項(xiàng)??梢酝ㄟ^(guò)聯(lián)合索引解決這個(gè)問(wèn)題,即在type, id兩列上建立一個(gè)聯(lián)合索引。
Using where
查詢的列未被索引覆蓋,where篩選條件非索引的前導(dǎo)列,Extra 中為 Using where。
所謂前導(dǎo)列,就是在創(chuàng)建復(fù)合索引語(yǔ)句的第一列或者連續(xù)的多列。比如通過(guò):CREATE INDEX comp_ind ON table1(x, y, z)創(chuàng)建索引,那么x,xy,xyz都是前導(dǎo)列,而yz,y,z這樣的就不是。
using where,using index
查詢的列被索引覆蓋,并且 where篩選條件是索引列之一但是不是索引的前導(dǎo)列,Extra中為Using where; Using index,意味著無(wú)法直接通過(guò)索引查找來(lái)查詢到符合條件的數(shù)據(jù);
查詢的列被索引覆蓋,并且where篩選條件是索引列前導(dǎo)列的一個(gè)范圍,同樣意味著無(wú)法直接通過(guò)索引查詢到符合條件的數(shù)據(jù)
Using index condition
查詢的列不全在索引中,where條件中是一個(gè)前導(dǎo)列的范圍
查詢列不完全被索引覆蓋,查詢條件完全可以使用到索引(進(jìn)行索引查找)
NULL(既沒(méi)有Using index,也沒(méi)有Using where Using index,也沒(méi)有using where)。
查詢的列未被索引覆蓋,并且where篩選條件是索引的前導(dǎo)列,意味著用到了索引,但是部分字段未被索引覆蓋,必須通過(guò)“回表”來(lái)實(shí)現(xiàn),不是純粹地用到了索引,也不是完全沒(méi)用到索引,Extra中為NULL(沒(méi)有信息)。
Using join buffer
使用了連接緩存。
小表驅(qū)動(dòng)大表
在表連接過(guò)程中。一般選擇小表作為驅(qū)動(dòng)表,大表作為被驅(qū)動(dòng)表。
驅(qū)動(dòng)表(小表)的連接字段無(wú)論建立沒(méi)建立索引都需要全表掃描的。被驅(qū)動(dòng)表(大表)如果在連接字段建立了索引,則可以走索引。如果沒(méi)有建立索引則也需要全表掃描。
兩張表連接的情況
被驅(qū)動(dòng)表的連接字段有索引:主鍵索引
對(duì)于驅(qū)動(dòng)表中的每一條數(shù)據(jù),到被驅(qū)動(dòng)表的聚簇索引上尋找其對(duì)應(yīng)的數(shù)據(jù)。
被驅(qū)動(dòng)表的連接字段有索引:二級(jí)索引
對(duì)于驅(qū)動(dòng)表上的每一條數(shù)據(jù),到被驅(qū)動(dòng)表的二次索引上尋找其對(duì)應(yīng)的數(shù)據(jù)id,然后再根據(jù)數(shù)據(jù)id到聚簇索引上尋找對(duì)應(yīng)的數(shù)據(jù)。
被驅(qū)動(dòng)表的連接字段沒(méi)有索引
對(duì)于驅(qū)動(dòng)表上的每一條數(shù)據(jù),都要到被驅(qū)動(dòng)表上進(jìn)行一次全表遍歷,找到對(duì)應(yīng)的數(shù)據(jù)。
join buffer的作用
就是針對(duì)被驅(qū)動(dòng)表的連接字段沒(méi)有索引的情況下需要進(jìn)行全表掃描,所以引入了join buffer內(nèi)存緩沖區(qū)來(lái)對(duì)這個(gè)全表掃描過(guò)程進(jìn)行優(yōu)化。
impossible where
where子句總是false,不能用來(lái)獲取任何元素。即篩選條件沒(méi)能篩選出任何數(shù)據(jù)。
select tables optimized away
在沒(méi)有 GROUPBY 子句的情況下,基于索引優(yōu)化 MIN/MAX操作。
distinct
優(yōu)化 distinct操作。在找到第一匹配的時(shí)候就停止找同樣的動(dòng)作。