explain所有人都應(yīng)該很熟悉,通過(guò)它我們可以知道SQL是如何執(zhí)行的,雖然不是100%管用,但是至少大多數(shù)場(chǎng)景通過(guò)explain的輸出結(jié)果我們能直觀的看到執(zhí)行計(jì)劃的相關(guān)信息。 早一些的版本explain還只能查看 剛開始我想寫這個(gè)的時(shí)候只是因?yàn)檫@個(gè)東西經(jīng)常性不用就忘記,寫了發(fā)現(xiàn)其實(shí)這個(gè)東西真的挺麻煩的,要把每個(gè)場(chǎng)景都整出來(lái)麻煩的很。 id查詢編號(hào),如果沒(méi)有子查詢或者聯(lián)合查詢的話,就只有一條,如果是聯(lián)合查詢的話,那么會(huì)出現(xiàn)一條id為null的記錄,并且標(biāo)志查詢結(jié)果,因?yàn)?code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 100, 65);">union結(jié)果會(huì)放到臨時(shí)表中,所以我們看到這里的表名是<union1,2>這種格式。 select_type關(guān)聯(lián)類型,決定訪問(wèn)表的方式。 SIMPLE 簡(jiǎn)單查詢,代表沒(méi)有子查詢或者 PRIMARY 如果不是簡(jiǎn)單查詢,那么最外層查詢就會(huì)被標(biāo)記成PRIMARY。 UNION&UNION RESULT 從上圖可以看出來(lái)了,包含聯(lián)合查詢,第一個(gè)被標(biāo)記成了 DERIVED 用來(lái)標(biāo)記出現(xiàn)在from里的子查詢,這個(gè)結(jié)果會(huì)放入臨時(shí)表中,也叫做派生表。 這個(gè)對(duì)于低版本的Mysql可能顯示是這樣的,高一點(diǎn)可能你看到的還是PRIMARY,因?yàn)楸籑ysql優(yōu)化了。我換一個(gè)版本的Mysql和SQL執(zhí)行可以驗(yàn)證到這個(gè)結(jié)果。 SUBQUERY 不在from里的子查詢。 DEPENDENT 代表關(guān)聯(lián)子查詢(子查詢使用了外部查詢包含的列),和 UNCACHEABLE 代表不能緩存的子查詢,也可以和 MATERIALIZED 物化子查詢是Mysql對(duì)子查詢的優(yōu)化,第一次執(zhí)行子查詢時(shí)會(huì)將結(jié)果保存到臨時(shí)表,物化子查詢只需要執(zhí)行一次。 比如上述DERIVED就是物化的一種體現(xiàn),與之對(duì)應(yīng)的就是DEPENDENT,每次子查詢都需要重新調(diào)用。 這個(gè)結(jié)果無(wú)法直觀的看出來(lái),可以用 table顯示表名,從上述的一些圖中可以觀察到UNION_RESULT和DERIVED顯示的表名都有一些自己的命名規(guī)則。 比如UNION_RESULT產(chǎn)生的是<unionM,N>,DERIVED產(chǎn)生的是 partitions數(shù)據(jù)的分區(qū)信息,沒(méi)有分區(qū)忽略就好了。 type關(guān)聯(lián)類型,決定通過(guò)什么方式找到每一行數(shù)據(jù)。以下按照速度由快到慢。 system>const>eq_ref>ref>fulltext>ref_or_null>index_merge>unique_subquery>index_subquery>range>index>ALL。 system&const 這通常是最快的查找方式,代表Mysql通過(guò)優(yōu)化最終轉(zhuǎn)換成常量查詢,最常規(guī)的做法就是直接通過(guò)主鍵或者唯一索引查詢。 而system是const的一個(gè)特例(只有一行數(shù)據(jù)的系統(tǒng)表),隨便找一張系統(tǒng)表,就插入一條數(shù)據(jù)就可以看到system了。 eq_ref 通常通過(guò)主鍵索引或者唯一索引查詢時(shí)會(huì)看到eq_ref,它最多只返回一條數(shù)據(jù)。 ref 也是通過(guò)索引查找,但是和eq_ref不同,ref可能匹配到多條符合條件的數(shù)據(jù),比如最左前綴匹配或者不是主鍵和唯一索引。 最簡(jiǎn)單的辦法,隨便查一個(gè)普通索引就可以看到。 fulltext 使用FULLTEXT索引 ref_or_null 和ref類似,但是還要進(jìn)行一次查詢找到NULL的數(shù)據(jù)。 這相當(dāng)于是對(duì)于IS NULL查詢的優(yōu)化,如果表數(shù)據(jù)量太少的話,你或許能看到這里類型是全表掃描。 index_merge 索引合并是在Mysql5.1之后引入的,就像下面的一個(gè)OR查詢,按照原來(lái)的想法要么用name的索引,要么就是用age的索引,有了索引合并就不一樣了。 對(duì)于這種單表查詢(無(wú)法跨表合并)用到了多個(gè)索引的情況,每個(gè)索引都可能返回一個(gè)結(jié)果,Mysql會(huì)對(duì)結(jié)果進(jìn)行取并集、交集,這就是索引合并了。 unique_subquery 按照官方文檔所說(shuō),unique_subquery只是eq_ref的一個(gè)特例,對(duì)于下圖中這種 由于Mysql會(huì)對(duì)select進(jìn)行優(yōu)化,基本無(wú)法出現(xiàn)這個(gè)場(chǎng)景,只能用update這種語(yǔ)句了。 index_subquery 和unique_subquery類似,只是針對(duì)的是非唯一索引。 range 看名字就知道,范圍查詢,其實(shí)就是帶有限制條件的索引掃描。 常見(jiàn)的范圍查詢比如 index 跟全表掃描類似,只是掃表是按照索引順序進(jìn)行。 ALL 全表掃描,沒(méi)啥好說(shuō)的。 possible_keys可以使用哪些索引。 key實(shí)際決定使用哪個(gè)索引。 key_len索引字段的可能最大長(zhǎng)度,不是表中實(shí)際數(shù)據(jù)使用的長(zhǎng)度。 ref表示key展示的索引實(shí)際使用的列或者常量。 rows查詢數(shù)據(jù)需要讀取的行數(shù),只是一個(gè)預(yù)估的數(shù)值,但是能很直觀的看出SQL的優(yōu)劣了。 filtered5.1版本之后新增字段,表示針對(duì)符合查詢條件的記錄數(shù)的百分比估算,用rows和filtered相乘可以計(jì)算出關(guān)聯(lián)表的行數(shù)。 Extra解析查詢的附加額外信息,這個(gè)太多了,有興趣可以自己看官方文檔,只列舉一些常見(jiàn)的。 Using index 使用覆蓋索引。 Using index condition 可以使用索引下推(不一定真的使用了),索引下推簡(jiǎn)單來(lái)說(shuō)就是加上了條件篩選,減少了回表的操作。 Using temporary 排序使用了臨時(shí)表。 Using filesort 使用外部索引文件排序,但是不能從這里看出是內(nèi)存還是磁盤排序,我們只能知道更消耗性能。 Using where where過(guò)濾,沒(méi)啥好說(shuō)的。 Zero limit 除非你寫個(gè)LIMIT 0。 Using sort_union(), Using union(), sing intersect() 使用了索引合并,參看上文。 總結(jié) |
|