Explain主要內(nèi)容
紅框里應(yīng)該是我們重點(diǎn)關(guān)注的较坛。
表名就是用到了哪些表捐迫,type是針對單表的訪問方法卢厂,就是在上文提到的。主要有如下:
const
當(dāng)我們根據(jù)主鍵或者唯一二級索引列與常數(shù)進(jìn)行等值匹配時河劝,對單表的訪問方法就是const
eq_ref
在連接查詢時壁榕,如果被驅(qū)動表是通過主鍵或者唯一二級索引列等值匹配的方式進(jìn)行訪問的(如果該主鍵或者唯一二級索引是聯(lián)合索引的話,所有的索引列都必須進(jìn)行等值比較)赎瞎,則對該被驅(qū)動表的訪問方法就是eq_ref
ref
當(dāng)通過普通的二級索引列與常量進(jìn)行等值匹配時來查詢某個表牌里,那么對該表的訪問方法就可能是ref,最開始舉過例子了务甥,就不重復(fù)舉例了牡辽。
range
如果使用索引獲取某些范圍區(qū)間的記錄,那么就可能使用到range訪問方法
index
當(dāng)我們可以使用索引覆蓋敞临,但需要掃描全部的索引記錄時态辛,該表的訪問方法就是index
ALL
這幾個效率是依次減低的,一定要避免ALL全表掃描挺尿,否則慢死了奏黑。
看看rows就知道了
最后看一下額外信息
Extra
顧名思義炊邦,Extra列是用來說明一些額外信息的,不過出現(xiàn)這些額外信息的時候攀涵,一般都不是好消息铣耘。
Using index
當(dāng)我們的查詢列表以及搜索條件中只包含屬于某個索引的列,也就是在可以使用索引覆蓋的情況下以故,在Extra列將會提示該額外信息蜗细。比方說下邊這個查詢中只需要用到idx_key1而不需要回表操作:
mysql> EXPLAIN SELECT key1 FROM s1 WHERE key1 ='a';
Using index condition
有些搜索條件中雖然出現(xiàn)了索引列,但卻不能使用到索引怒详,比如下邊這個查詢:
SELECT * FROM s1 WHERE key1 >'z'AND key1 LIKE'%a';
其中的key1 > 'z'可以使用到索引炉媒,但是key1 LIKE '%a'卻無法使用到索引,在以前版本的MySQL中昆烁,是按照下邊步驟來執(zhí)行這個查詢的:
先根據(jù)key1 > 'z'這個條件吊骤,從二級索引idx_key1中獲取到對應(yīng)的二級索引記錄。
根據(jù)上一步驟得到的二級索引記錄中的主鍵值進(jìn)行回表静尼,找到完整的用戶記錄再檢測該記錄是否符合key1 LIKE '%a'這個條件白粉,將符合條件的記錄加入到最后的結(jié)果集。
但是雖然key1 LIKE '%a'不能組成范圍區(qū)間參與range訪問方法的執(zhí)行鼠渺,但這個條件畢竟只涉及到了key1列鸭巴,所以設(shè)計MySQL的大叔把上邊的步驟改進(jìn)了一下:
先根據(jù)key1 > 'z'這個條件,定位到二級索引idx_key1中對應(yīng)的二級索引記錄拦盹。
對于指定的二級索引記錄鹃祖,先不著急回表,而是先檢測一下該記錄是否滿足key1 LIKE '%a'這個條件普舆,如果這個條件不滿足恬口,則該二級索引記錄壓根兒就沒必要回表。
對于滿足key1 LIKE '%a'這個條件的二級索引記錄執(zhí)行回表操作沼侣。
我們說回表操作其實(shí)是一個隨機(jī)IO祖能,比較耗時,所以上述修改雖然只改進(jìn)了一點(diǎn)點(diǎn)蛾洛,但是可以省去好多回表操作的成本芯杀。設(shè)計MySQL的大叔們把他們的這個改進(jìn)稱之為索引條件下推(英文名:Index Condition Pushdown)。
如果在查詢語句的執(zhí)行過程中將要使用索引條件下推這個特性雅潭,在Extra列中將會顯示Using index condition,比如這樣:
mysql> EXPLAIN SELECT * FROM s1 WHERE key1 >'z'AND key1 LIKE'%b';??
Using where
當(dāng)我們使用全表掃描來執(zhí)行對某個表的查詢却特,并且該語句的WHERE子句中有針對該表的搜索條件時扶供,在Extra列中會提示上述額外信息。比如下邊這個查詢:
mysql> EXPLAIN SELECT * FROM s1 WHERE common_field ='a';
當(dāng)使用索引訪問來執(zhí)行對某個表的查詢裂明,并且該語句的WHERE子句中有除了該索引包含的列之外的其他搜索條件時椿浓,在Extra列中也會提示上述額外信息。比如下邊這個查詢雖然使用idx_key1索引執(zhí)行查詢,但是搜索條件中除了包含key1的搜索條件key1 = 'a'扳碍,還有包含common_field的搜索條件提岔,所以Extra列會顯示Using where的提示:
mysql> EXPLAIN SELECT * FROM s1 WHERE key1 ='a'AND common_field ='a';
Using filesort
有一些情況下對結(jié)果集中的記錄進(jìn)行排序是可以使用到索引的,比如下邊這個查詢:
mysql> EXPLAIN SELECT * FROM s1 ORDER BY key1 LIMIT 10;
這個查詢語句可以利用idx_key1索引直接取出key1列的10條記錄笋敞,然后再進(jìn)行回表操作就好了碱蒙。但是很多情況下排序操作無法使用到索引,只能在內(nèi)存中(記錄較少的時候)或者磁盤中(記錄較多的時候)進(jìn)行排序夯巷,設(shè)計MySQL的大叔把這種在內(nèi)存中或者磁盤上進(jìn)行排序的方式統(tǒng)稱為文件排序(英文名:filesort)赛惩。如果某個查詢需要使用文件排序的方式執(zhí)行查詢,就會在執(zhí)行計劃的Extra列中顯示Using filesort提示趁餐,比如這樣:
mysql> EXPLAIN SELECT * FROM s1 ORDER BY common_field LIMIT 10;
需要注意的是喷兼,如果查詢中需要使用filesort的方式進(jìn)行排序的記錄非常多,那么這個過程是很耗費(fèi)性能的后雷,我們最好想辦法將使用文件排序的執(zhí)行方式改為使用索引進(jìn)行排序季惯。
Using temporary
在許多查詢的執(zhí)行過程中,MySQL可能會借助臨時表來完成一些功能臀突,比如去重勉抓、排序之類的,比如我們在執(zhí)行許多包含DISTINCT惧辈、GROUP BY琳状、UNION等子句的查詢過程中,如果不能有效利用索引來完成查詢盒齿,MySQL很有可能尋求通過建立內(nèi)部的臨時表來執(zhí)行查詢念逞。如果查詢中使用到了內(nèi)部的臨時表,在執(zhí)行計劃的Extra列將會顯示Using temporary提示边翁,比方說這樣:
mysql> EXPLAIN SELECT DISTINCT common_field FROM s1;
再比如:
mysql> EXPLAIN SELECT common_field, COUNT(*) AS amount FROM s1 GROUP BY common_field;
不知道大家注意到?jīng)]有翎承,上述執(zhí)行計劃的Extra列不僅僅包含Using temporary提示,還包含Using filesort提示符匾,可是我們的查詢語句中明明沒有寫ORDER BY子句呀叨咖?這是因為MySQL會在包含GROUP BY子句的查詢中默認(rèn)添加上ORDER BY子句,也就是說上述查詢其實(shí)和下邊這個查詢等價:
EXPLAIN SELECT common_field, COUNT(*) AS amount FROM s1 GROUP BY common_field ORDER BY common_field;
如果我們并不想為包含GROUP BY子句的查詢進(jìn)行排序啊胶,需要我們顯式的寫上ORDER BY NULL甸各,就像這樣:
mysql> EXPLAIN SELECT common_field, COUNT(*) AS amount FROM s1 GROUP BY common_field ORDER BY NULL;
這回執(zhí)行計劃中就沒有Using filesort的提示了,也就意味著執(zhí)行查詢時可以省去對記錄進(jìn)行文件排序的成本了焰坪。
另外趣倾,執(zhí)行計劃中出現(xiàn)Using temporary并不是一個好的征兆,因為建立與維護(hù)臨時表要付出很大成本的某饰,所以我們最好能使用索引來替代掉使用臨時表儒恋,比方說下邊這個包含GROUP BY子句的查詢就不需要使用臨時表:
mysql> EXPLAIN SELECT key1, COUNT(*) AS amount FROM s1 GROUP BY key1;
從Extra的Using index的提示里我們可以看出善绎,上述查詢只需要掃描idx_key1索引就可以搞定了,不再需要臨時表了诫尽。