MySQL數(shù)據(jù)庫(kù)下的Explain命令深度解析

Explain是一個(gè)非常有的命令毙芜,可以用來(lái)獲取關(guān)于查詢執(zhí)行計(jì)劃的信息间影,以及如何解釋輸出颜屠。Explain命令是查看查詢優(yōu)化器如何決定執(zhí)行查詢的主要方法欧募。這個(gè)功能有一定的局限性压状,并不總是會(huì)說(shuō)出真相,但是它的輸出是可以獲取的最好信息槽片,值得花時(shí)間了解何缓,可以學(xué)習(xí)到查詢是如何執(zhí)行的肢础。

調(diào)用Explain

要使用Explain,只需在查詢中的select關(guān)鍵字之前增加Explain這個(gè)詞碌廓。MySQL會(huì)在查詢上設(shè)置一個(gè)標(biāo)記传轰。當(dāng)執(zhí)行查詢時(shí),這個(gè)標(biāo)記會(huì)使其返回關(guān)于在執(zhí)行計(jì)劃中每一步的信息谷婆,而不是執(zhí)行它慨蛙。

我們來(lái)簡(jiǎn)單看一下例子:可能是最簡(jiǎn)單的Explain結(jié)果


在查詢中每個(gè)表在輸出中只有一行。如果查詢是兩個(gè)表的聯(lián)接纪挎,那么輸出中將有兩行期贫。別名表單算為一個(gè)表。

Explain有兩個(gè)主要的變種

Explain extended看起來(lái)和正常的explain行為一樣异袄,但它會(huì)告訴服務(wù)器“逆向編譯”執(zhí)行計(jì)劃為一個(gè)select語(yǔ)句通砍。可以通過(guò)緊接其后運(yùn)行showwarnings看到這個(gè)生成的語(yǔ)句烤蜕。這個(gè)語(yǔ)句直接來(lái)自執(zhí)行計(jì)劃封孙,而不是原SQL語(yǔ)句,到這點(diǎn)上已經(jīng)變成一個(gè)數(shù)據(jù)結(jié)構(gòu)讽营。大部分場(chǎng)景下虎忌,它都是優(yōu)化過(guò)的,跟原語(yǔ)句不相同橱鹏,可以學(xué)習(xí)查詢優(yōu)化器到底是如何轉(zhuǎn)化語(yǔ)句的膜蠢。

Explain partitions會(huì)顯示查詢將訪問(wèn)的分區(qū),如果查詢是基于分區(qū)表的話莉兰。

一般認(rèn)為增加explain時(shí)挑围,MySQL語(yǔ)句不會(huì)執(zhí)行查詢,這是錯(cuò)誤的糖荒。如果查詢?cè)趂rom子句中包括子查詢贪惹,那么MySQL實(shí)際上是會(huì)執(zhí)行子查詢,將其結(jié)果放在一個(gè)臨時(shí)表中寂嘉,然后完成外層查詢優(yōu)化。

前面簡(jiǎn)單解釋了一下Explain可以做到的事情枫绅,但是Explain也有自身的一些限制:

Explain根本不會(huì)告訴你觸發(fā)器泉孩,存儲(chǔ)過(guò)程或者UFD會(huì)如何影響查詢。

它不支持存儲(chǔ)過(guò)程并淋,盡管可以手動(dòng)抽取查詢并單獨(dú)地對(duì)其進(jìn)行explain操作寓搬。

它并不會(huì)告訴你MySQL在查詢執(zhí)行中所做的特定優(yōu)化。

它并不會(huì)顯示關(guān)于查詢的執(zhí)行計(jì)劃的所有信息县耽。

它并不區(qū)分具有相同名字的事物句喷。比如镣典,對(duì)內(nèi)存排序和臨時(shí)文件都用“filesort”,對(duì)磁盤(pán)上和內(nèi)存中的臨時(shí)表都顯示“Using temporary”唾琼。

可能會(huì)誤導(dǎo)兄春。比如,會(huì)對(duì)一個(gè)有著很小的LIMIT的查詢顯示全索引掃描锡溯。

重寫(xiě)非select查詢

MySQL Explain只能解釋select查詢赶舆,并不會(huì)對(duì)存儲(chǔ)過(guò)程調(diào)用和insert,update祭饭,delete或其他語(yǔ)句做解釋芜茵。但是,我們可以重寫(xiě)這些非select語(yǔ)句來(lái)利用explain倡蝙。為了利用explain九串,我們需要將這些語(yǔ)句轉(zhuǎn)化成一個(gè)等價(jià)的訪問(wèn)所有相同列的select,所有需要的列必須在select列表寺鸥,關(guān)聯(lián)子句猪钮,或者where子句中。

Explain中的列

01

id列

這一列總是包含一個(gè)編號(hào)析既,標(biāo)示select所屬的行躬贡。數(shù)字越大越先執(zhí)行,如果說(shuō)數(shù)字一樣大眼坏,那么就從上往下依次執(zhí)行拂玻,id列為null的就表示這是一個(gè)結(jié)果集,不需要使用它來(lái)進(jìn)行查詢宰译。

02

select_type列

這一列顯示了對(duì)應(yīng)行是簡(jiǎn)單還是復(fù)雜select檐蚜。

常見(jiàn)的有:

A:simple:表示不包含union操作或者不包含子查詢的簡(jiǎn)單select查詢。有連接查詢時(shí)沿侈,外層的查詢?yōu)閟imple闯第,且只有一個(gè)

B:primary:一個(gè)需要union操作或者含有子查詢的select,位于最外層的單位查詢的select_type即為primary缀拭。且只有一個(gè)

C:union:union連接的兩個(gè)select查詢咳短,第一個(gè)查詢是dervied派生表,除了第一個(gè)表外蛛淋,第二個(gè)以后的表select_type都是union

D:dependent union:與union一樣咙好,出現(xiàn)在union 或union all語(yǔ)句中,但是這個(gè)查詢要受到外部查詢的影響

E:union result:包含union的結(jié)果集褐荷,在union和union all語(yǔ)句中,因?yàn)樗恍枰獏⑴c查詢勾效,所以id字段為null

F:subquery:除了from字句中包含的子查詢外,其他地方出現(xiàn)的子查詢都可能是subquery

G:dependent subquery:與dependentunion類(lèi)似,表示這個(gè)subquery的查詢要受到外部表查詢的影響

H:derived:from字句中出現(xiàn)的子查詢层宫,也叫做派生表杨伙,其他數(shù)據(jù)庫(kù)中可能叫做內(nèi)聯(lián)視圖或嵌套select

03

table列

這一列顯示了對(duì)應(yīng)行正在訪問(wèn)查詢的表名,如果查詢使用了別名萌腿,那么這里顯示的是別名限匣,如果不涉及對(duì)數(shù)據(jù)表的操作,那么這顯示為null哮奇,如果顯示為尖括號(hào)括起來(lái)的<derived N>就表示這個(gè)是臨時(shí)表膛腐,后邊的N就是執(zhí)行計(jì)劃中的id,表示結(jié)果來(lái)自于這個(gè)查詢產(chǎn)生鼎俘。如果是尖括號(hào)括起來(lái)的<union M,N>哲身,與<derived N>類(lèi)似,也是一個(gè)臨時(shí)表贸伐,表示這個(gè)結(jié)果來(lái)自于union查詢的id為M,N的結(jié)果集勘天。

04

type列

這一列顯示了訪問(wèn)類(lèi)型,即MySQL決定如何查找表中的行捉邢。

依次從好到差:system脯丝,const,eq_ref伏伐,ref宠进,fulltext,ref_or_null藐翎,unique_subquery材蹬,index_subquery,range吝镣,index_merge堤器,index,ALL末贾,除了all之外闸溃,其他的type都可以使用到索引,除了index_merge之外拱撵,其他的type只可以用到一個(gè)索引

A:system:表中只有一行數(shù)據(jù)或者是空表辉川,且只能用于myisam和memory表。如果是Innodb引擎表拴测,type列在這個(gè)情況通常都是all或者index

B:const:使用唯一索引或者主鍵员串,返回記錄一定是1行記錄的等值where條件時(shí),通常type是const昼扛。其他數(shù)據(jù)庫(kù)也叫做唯一索引掃描

C:eq_ref:出現(xiàn)在要連接過(guò)個(gè)表的查詢計(jì)劃中,驅(qū)動(dòng)表只返回一行數(shù)據(jù),且這行數(shù)據(jù)是第二個(gè)表的主鍵或者唯一索引抄谐,且必須為not null渺鹦,唯一索引和主鍵是多列時(shí),只有所有的列都用作比較時(shí)才會(huì)出現(xiàn)eq_ref

D:ref:不像eq_ref那樣要求連接順序蛹含,也沒(méi)有主鍵和唯一索引的要求毅厚,只要使用相等條件檢索時(shí)就可能出現(xiàn),常見(jiàn)與輔助索引的等值查找浦箱∥ⅲ或者多列主鍵、唯一索引中酷窥,使用第一個(gè)列之外的列作為等值查找也會(huì)出現(xiàn)咽安,總之,返回?cái)?shù)據(jù)不唯一的等值查找就可能出現(xiàn)蓬推。

E:fulltext:全文索引檢索妆棒,要注意,全文索引的優(yōu)先級(jí)很高沸伏,若全文索引和普通索引同時(shí)存在時(shí)糕珊,mysql不管代價(jià),優(yōu)先選擇使用全文索引

F:ref_or_null:與ref方法類(lèi)似毅糟,只是增加了null值的比較红选。實(shí)際用的不多。

G:unique_subquery:用于where中的in形式子查詢姆另,子查詢返回不重復(fù)值唯一值

H:index_subquery:用于in形式子查詢使用到了輔助索引或者in常數(shù)列表喇肋,子查詢可能返回重復(fù)值,可以使用索引將子查詢?nèi)ブ亍?/p>

I:range:索引范圍掃描蜕青,常見(jiàn)于使用>,<,isnull,between ,in ,like等運(yùn)算符的查詢中苟蹈。

J:index_merge:表示查詢使用了兩個(gè)以上的索引,最后取交集或者并集右核,常見(jiàn)and 慧脱,or的條件使用了不同的索引,官方排序這個(gè)在ref_or_null之后贺喝,但是實(shí)際上由于要讀取所個(gè)索引菱鸥,性能可能大部分時(shí)間都不如range

K:index:索引全表掃描,把索引從頭到尾掃一遍躏鱼,常見(jiàn)于使用索引列就可以處理不需要讀取數(shù)據(jù)文件的查詢氮采、可以使用索引排序或者分組的查詢。

L:all:這個(gè)就是全表掃描數(shù)據(jù)文件染苛,然后再在server層進(jìn)行過(guò)濾返回符合要求的記錄鹊漠。

05

possible_keys列

查詢可能使用到的索引都會(huì)在這里列出來(lái)主到。這個(gè)列表是優(yōu)化過(guò)程早期創(chuàng)建的,因此有些羅列出來(lái)的索引有可能后續(xù)是沒(méi)用的躯概。

06

key列

顯示了查詢真正使用到的索引登钥,select_type為index_merge時(shí),這里可能出現(xiàn)兩個(gè)以上的索引娶靡,其他的select_type這里只會(huì)出現(xiàn)一個(gè)牧牢。

如果該索引沒(méi)有出現(xiàn)在possible_keys列中,那么MySQL選用它是出于另外的原因姿锭,比如選擇了一個(gè)覆蓋索引塔鳍。

possible_keys揭示了哪一個(gè)索引能有助于高效地行查找,key顯示了優(yōu)化采用哪一個(gè)索引可以最小化查詢成本呻此。

07

key_len列

用于處理查詢的索引長(zhǎng)度轮纫,如果是單列索引,那就整個(gè)索引長(zhǎng)度算進(jìn)去趾诗,如果是多列索引蜡感,那么查詢不一定都能使用到所有的列,具體使用到了多少個(gè)列的索引恃泪,這里就會(huì)計(jì)算進(jìn)去郑兴,沒(méi)有使用到的列,這里不會(huì)計(jì)算進(jìn)去贝乎。留意下這個(gè)列的值情连,算一下你的多列索引總長(zhǎng)度就知道有沒(méi)有使用到所有的列了。要注意览效,mysql的ICP特性使用到的索引不會(huì)計(jì)入其中却舀。另外,key_len只計(jì)算where條件用到的索引長(zhǎng)度锤灿,而排序和分組就算用到了索引挽拔,也不會(huì)計(jì)算到key_len中。

08

ref列

如果是使用的常數(shù)等值查詢但校,這里會(huì)顯示const螃诅,如果是連接查詢,被驅(qū)動(dòng)表的執(zhí)行計(jì)劃這里會(huì)顯示驅(qū)動(dòng)表的關(guān)聯(lián)字段状囱,如果是條件使用了表達(dá)式或者函數(shù)术裸,或者條件列發(fā)生了內(nèi)部隱式轉(zhuǎn)換,這里可能顯示為func

09

rows列

這里是執(zhí)行計(jì)劃中估算的掃描行數(shù)亭枷,不是精確值

10

extra列

這個(gè)列可以顯示的信息非常多袭艺,有幾十種,常用的有

A:distinct:在select部分使用了distinc關(guān)鍵字

B:no tables used:不帶from字句的查詢或者Fromdual查詢

C:使用not in()形式子查詢或notexists運(yùn)算符的連接查詢叨粘,這種叫做反連接猾编。即瘤睹,一般連接查詢是先查詢內(nèi)表,再查詢外表答倡,反連接就是先查詢外表默蚌,再查詢內(nèi)表。

D:using filesort:排序時(shí)無(wú)法使用到索引時(shí)苇羡,就會(huì)出現(xiàn)這個(gè)。常見(jiàn)于order by和group by語(yǔ)句中

E:using index:查詢時(shí)不需要回表查詢鼻弧,直接通過(guò)索引就可以獲取查詢的數(shù)據(jù)设江。

F:using join buffer(block nestedloop),using join buffer(batched key accss):5.6.x之后的版本優(yōu)化關(guān)聯(lián)查詢的BNL攘轩,BKA特性叉存。主要是減少內(nèi)表的循環(huán)數(shù)量以及比較順序地掃描查詢。

G:using sort_union度帮,using_union歼捏,usingintersect,using sort_intersection:

using intersect:表示使用and的各個(gè)索引的條件時(shí)笨篷,該信息表示是從處理結(jié)果獲取交集

using union:表示使用or連接各個(gè)使用索引的條件時(shí)瞳秽,該信息表示從處理結(jié)果獲取并集

using sort_union和usingsort_intersection:與前面兩個(gè)對(duì)應(yīng)的類(lèi)似,只是他們是出現(xiàn)在用and和or查詢信息量大時(shí)率翅,先查詢主鍵练俐,然后進(jìn)行排序合并后,才能讀取記錄并返回冕臭。

H:using temporary:表示使用了臨時(shí)表存儲(chǔ)中間結(jié)果腺晾。臨時(shí)表可以是內(nèi)存臨時(shí)表和磁盤(pán)臨時(shí)表,執(zhí)行計(jì)劃中看不出來(lái)辜贵,需要查看status變量悯蝉,used_tmp_table,used_tmp_disk_table才能看出來(lái)托慨。

I:using where:表示存儲(chǔ)引擎返回的記錄并不是所有的都滿足查詢條件鼻由,需要在server層進(jìn)行過(guò)濾。查詢條件中分為限制條件和檢查條件榴芳,5.6之前嗡靡,存儲(chǔ)引擎只能根據(jù)限制條件掃描數(shù)據(jù)并返回,然后server層根據(jù)檢查條件進(jìn)行過(guò)濾再返回真正符合查詢的數(shù)據(jù)窟感。5.6.x之后支持ICP特性讨彼,可以把檢查條件也下推到存儲(chǔ)引擎層,不符合檢查條件和限制條件的數(shù)據(jù)柿祈,直接不讀取哈误,這樣就大大減少了存儲(chǔ)引擎掃描的記錄數(shù)量哩至。extra列顯示using index condition

J:firstmatch(tb_name):5.6.x開(kāi)始引入的優(yōu)化子查詢的新特性之一,常見(jiàn)于where字句含有in()類(lèi)型的子查詢蜜自。如果內(nèi)表的數(shù)據(jù)量比較大菩貌,就可能出現(xiàn)這個(gè)

K:loosescan(m..n):5.6.x之后引入的優(yōu)化子查詢的新特性之一,在in()類(lèi)型的子查詢中重荠,子查詢返回的可能有重復(fù)記錄時(shí)箭阶,就可能出現(xiàn)這個(gè)

除了這些之外,還有很多查詢數(shù)據(jù)字典庫(kù)戈鲁,執(zhí)行計(jì)劃過(guò)程中就發(fā)現(xiàn)不可能存在結(jié)果的一些提示信息

11

filtered列

使用explain extended時(shí)會(huì)出現(xiàn)這個(gè)列仇参,5.7之后的版本默認(rèn)就有這個(gè)字段,不需要使用explain extended了婆殿。這個(gè)字段表示存儲(chǔ)引擎返回的數(shù)據(jù)在server層過(guò)濾后诈乒,剩下多少滿足查詢的記錄數(shù)量的比例,注意是百分比婆芦,不是具體記錄數(shù)怕磨。


縱向表結(jié)構(gòu)輸出

在查詢過(guò)程中,有時(shí)候信息太多的時(shí)候消约,橫向輸出會(huì)特別不容易讀取肠鲫,這時(shí)候,我們可以使用G將結(jié)果進(jìn)行格式轉(zhuǎn)換荆陆,將橫向的表結(jié)構(gòu)會(huì)轉(zhuǎn)為使用縱向表結(jié)構(gòu)輸出滩届,利于閱讀。

這個(gè)格式化輸出也可以用在select語(yǔ)句后被啼。

作  者:Testfan Chris

出  處:微信公眾號(hào):自動(dòng)化軟件測(cè)試平臺(tái)

版權(quán)說(shuō)明:歡迎轉(zhuǎn)載帜消,但必須注明出處,并在文章頁(yè)面明顯位置給出文章鏈接

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末浓体,一起剝皮案震驚了整個(gè)濱河市泡挺,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌命浴,老刑警劉巖娄猫,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異生闲,居然都是意外死亡媳溺,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén)碍讯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)悬蔽,“玉大人,你說(shuō)我怎么就攤上這事捉兴⌒В” “怎么了录语?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)禾乘。 經(jīng)常有香客問(wèn)我澎埠,道長(zhǎng),這世上最難降的妖魔是什么始藕? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任蒲稳,我火速辦了婚禮,結(jié)果婚禮上伍派,老公的妹妹穿的比我還像新娘弟塞。我一直安慰自己,他們只是感情好拙已,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著摧冀,像睡著了一般倍踪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上索昂,一...
    開(kāi)封第一講書(shū)人閱讀 49,185評(píng)論 1 284
  • 那天建车,我揣著相機(jī)與錄音,去河邊找鬼椒惨。 笑死缤至,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的康谆。 我是一名探鬼主播领斥,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼沃暗!你這毒婦竟也來(lái)了月洛?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤孽锥,失蹤者是張志新(化名)和其女友劉穎嚼黔,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體惜辑,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡唬涧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盛撑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碎节。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖撵彻,靈堂內(nèi)的尸體忽然破棺而出钓株,到底是詐尸還是另有隱情实牡,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布轴合,位于F島的核電站创坞,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏受葛。R本人自食惡果不足惜题涨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望总滩。 院中可真熱鬧纲堵,春花似錦、人聲如沸闰渔。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)冈涧。三九已至茂附,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間督弓,已是汗流浹背营曼。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留愚隧,地道東北人蒂阱。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像狂塘,于是被迫代替她去往敵國(guó)和親录煤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容