MySQL 之 explain
explain 介紹
explain顯示了MySQL如何使用索引來(lái)處理select語(yǔ)句以及連接表。可以幫助選擇更好的索引和寫出更優(yōu)化的查詢語(yǔ)句。簡(jiǎn)單講,它的作用就是分析查詢性能。explain + 查詢SQL - 用于顯示SQL執(zhí)行信息參數(shù),根據(jù)參考信息可以進(jìn)行SQL優(yōu)化
示例:mysql> explain select * from (select nid,name from tb1 where nid < 10) as B; +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+ | 1 | PRIMARY | | ALL | NULL | NULL | NULL | NULL | 9 | NULL | | 2 | DERIVED | tb1 | range | PRIMARY | PRIMARY | 8 | NULL | 9 | Using where | +----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+id
查詢順序標(biāo)識(shí),每個(gè) SELECT 都會(huì)自動(dòng)分配一個(gè)唯一的標(biāo)識(shí)符。列數(shù)字越大越先執(zhí)行,如果數(shù)字一樣大,那么就從上往下依次執(zhí)行,id列為null的就表示這是一個(gè)結(jié)果集,不需要使用它來(lái)進(jìn)行查詢,例如使用union連接可能為null
select_type 查詢類型
- simple:表示不需要union操作或者不包含子查詢的簡(jiǎn)單select查詢。有連接查詢時(shí),外層的查詢?yōu)閟imple,且只有一個(gè)
- primary:一個(gè)需要union操作或者含有子查詢的select,位于最外層的單位查詢的select_type即為primary。且只有一個(gè)
- union:union連接的兩個(gè)select查詢,第一個(gè)查詢是dervied派生表,除了第一個(gè)表外,第二個(gè)以后的表select_type都是union
- dependent union:與union一樣,出現(xiàn)在union 或union all語(yǔ)句中,但是這個(gè)查詢要受到外部查詢的影響
- union result:包含union的結(jié)果集,在union和union all語(yǔ)句中,因?yàn)樗恍枰獏⑴c查詢,所以id字段為null
- subquery:除了from字句中包含的子查詢外,其他地方出現(xiàn)的子查詢都可能是subquery
- dependent subquery:與dependent union類似,表示這個(gè)subquery的查詢要受到外部表查詢的影響
- derived:from字句中出現(xiàn)的子查詢,也叫做派生表,其他數(shù)據(jù)庫(kù)中可能叫做內(nèi)聯(lián)視圖或嵌套select
? ? ...
table
顯示的查詢表名,如果查詢使用了別名,那么這里顯示的是別名,如果不涉及對(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>類似,也是一個(gè)臨時(shí)表,表示這個(gè)結(jié)果來(lái)自于union查詢的id為M,N的結(jié)果集
type
依次從好到差:system,const,eq_ref,ref,fulltext,ref_or_null,unique_subquery,index_subquery,range,index_merge,index,all,除了all之外,其他的type都可以使用到索引,除了index_merge之外,其他的type只可以用到一個(gè)索引
- system:表中只有一行數(shù)據(jù)或者是空表,且只能用于myisam和memory表。如果是Innodb引擎表,type列在這個(gè)情況通常都是all或者index,這是const聯(lián)接類型的一個(gè)特例。select * from (select nid from tb1 where nid = 1) as A;
- const:使用唯一索引或者主鍵,返回記錄一定是1行記錄的等值where條件時(shí),通常type是const。其他數(shù)據(jù)庫(kù)也叫做唯一索引掃描select nid from tb1 where nid = 2 ;
- eq_ref:出現(xiàn)在要連接過(guò)個(gè)表的查詢計(jì)劃中,驅(qū)動(dòng)表只返回一行數(shù)據(jù),且這行數(shù)據(jù)是第二個(gè)表的主鍵或者唯一索引,且必須為not null,唯一索引和主鍵是多列時(shí),只有所有的列都用作比較時(shí)才會(huì)出現(xiàn)eq_ref。select tb2.nid,tb1.name from tb2 left join tb1 on tb2.nid = tb1.nid;
- ref:根據(jù)索引查找一個(gè)或多個(gè)值。此類型通常出現(xiàn)在多表的 join 查詢, 針對(duì)于非唯一或非主鍵索引, 或者是使用了 最左前綴 規(guī)則索引的查詢。不像 eq_ref 那樣要求連接順序,也沒(méi)有主鍵和唯一索引的要求,只要使用相等條件檢索時(shí)就可能出現(xiàn),常見(jiàn)與輔助索引的等值查找。或者多列主鍵、唯一索引中,使用第一個(gè)列之外的列作為等值查找也會(huì)出現(xiàn),總之,返回?cái)?shù)據(jù)不唯一的等值查找就可能出現(xiàn)。
- fulltext:全文索引檢索,要注意,全文索引的優(yōu)先級(jí)很高,若全文索引和普通索引同時(shí)存在時(shí),mysql不管代價(jià),優(yōu)先選擇使用全文索引
- ref_or_null:與ref方法類似,只是增加了null值的比較。實(shí)際用的不多。
- unique_subquery:用于where中的in形式子查詢,子查詢返回不重復(fù)值唯一值
- index_subquery:用于in形式子查詢使用到了輔助索引或者in常數(shù)列表,子查詢可能返回重復(fù)值,可以使用索引將子查詢?nèi)ブ亍?/li>
- range:表示使用索引范圍查詢, 通過(guò)索引字段范圍獲取表中部分?jǐn)?shù)據(jù)記錄. 這個(gè)類型通常出現(xiàn)在 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN() 操作中當(dāng) type 是 range 時(shí), 那么 EXPLAIN 輸出的 ref 字段為 NULL, 并且 key_len 字段是此次查詢中使用到的索引的最長(zhǎng)的那個(gè)。
- index_merge:表示查詢使用了兩個(gè)以上的索引,最后取交集或者并集,常見(jiàn)and ,or的條件使用了不同的索引,官方排序這個(gè)在ref_or_null之后,但是實(shí)際上由于要讀取所個(gè)索引,性能可能大部分時(shí)間都不如range
- index:表示全索引掃描(full index scan), 和 ALL 類型類似, 只不過(guò) ALL 類型是全表掃描, 而 index 類型則僅僅掃描所有的索引, 而不掃描數(shù)據(jù).index 類型通常出現(xiàn)在: 所要查詢的數(shù)據(jù)直接在索引樹中就可以獲取到, 而不需要掃描數(shù)據(jù). 當(dāng)是這種情況時(shí), Extra 字段 會(huì)顯示 Using index.比如, 我們查詢的 name 字段恰好是一個(gè)索引, 因此我們直接從索引中獲取數(shù)據(jù)就可以滿足查詢的需求了, 而不需要查詢表中的數(shù)據(jù). 因此這樣的情況下, type 的值是 index, 并且 Extra 的值是 Using index.
- all:這個(gè)就是全表掃描數(shù)據(jù)文件,然后再在server層進(jìn)行過(guò)濾返回符合要求的記錄。這個(gè)類型的查詢是性能最差的查詢之一,最不建議使用
possible_keys ?
查詢可能使用到的索引都會(huì)在這里列出來(lái)
key
查詢真正使用到的索引,select_type 為 index_merge 時(shí),這里可能出現(xiàn)兩個(gè)以上的索引,其他的select_type這里只會(huì)出現(xiàn)一個(gè)
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中。
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
rows ?
mysql估計(jì)為了找到所需的行而要讀取的行數(shù) ------ 只是預(yù)估值
extra
這個(gè)列可以顯示的信息非常多,有幾十種,常用的有:
- distinct:在select部分使用了distinc關(guān)鍵字
- no tables used:不帶from字句的查詢或者From dual查詢
- using filesort:排序時(shí)無(wú)法使用到索引時(shí),就會(huì)出現(xiàn)這個(gè)。常見(jiàn)于order by和group by語(yǔ)句中
- using index:查詢時(shí)不需要回表查詢,直接通過(guò)覆蓋索引就可以獲取查詢的數(shù)據(jù)。
- using join buffer(block nested loop),using join buffer(batched key accss):5.6.x之后的版本優(yōu)化關(guān)聯(lián)查詢的BNL,BKA特性。主要是減少內(nèi)表的循環(huán)數(shù)量以及比較順序地掃描查詢。
- using intersect:表示使用and的各個(gè)索引的條件時(shí),該信息表示是從處理結(jié)果獲取交集
- using union:表示使用or連接各個(gè)使用索引的條件時(shí),該信息表示從處理結(jié)果獲取并集
- using sort_union和using sort_intersection:與前面兩個(gè)對(duì)應(yīng)的類似,只是他們是出現(xiàn)在用and和or查詢信息量大時(shí),先查詢主鍵,然后進(jìn)行排序合并后,才能讀取記錄并返回。
- using temporary:表示使用了臨時(shí)表存儲(chǔ)中間結(jié)果。臨時(shí)表可以是內(nèi)存臨時(shí)表和磁盤臨時(shí)表,執(zhí)行計(jì)劃中看不出來(lái),需要查看status變量,used_tmp_table,used_tmp_disk_table才能看出來(lá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。mysql服務(wù)器將在存儲(chǔ)引擎檢索行后再進(jìn)行過(guò)濾,許多where條件里涉及索引中的列,當(dāng)(并且如果)它讀取索引時(shí),就能被存儲(chǔ)引擎檢驗(yàn),因此不是所有帶where子句的查詢都會(huì)顯示“Using where”。有時(shí)“Using where”的出現(xiàn)就是一個(gè)暗示:查詢可受益于不同的索引。
- firstmatch(tb_name):5.6.x開(kāi)始引入的優(yōu)化子查詢的新特性之一,常見(jiàn)于where字句含有in()類型的子查詢。如果內(nèi)表的數(shù)據(jù)量比較大,就可能出現(xiàn)這個(gè)
- loosescan(m..n):5.6.x之后引入的優(yōu)化子查詢的新特性之一,在in()類型的子查詢中,子查詢返回的可能有重復(fù)記錄時(shí),就可能出現(xiàn)這個(gè)
filtered
使用explain extended時(shí)會(huì)出現(xiàn)這個(gè)列,5.7之后的版本默認(rèn)就有這個(gè)字段,不需要使用explain extended了。這個(gè)字段表示存儲(chǔ)引擎返回的數(shù)據(jù)在server層過(guò)濾后,剩下多少滿足查詢的記錄數(shù)量的比例,注意是百分比,不是具體記錄數(shù)。
| id | SELECT識(shí)別符。這是SELECT的查詢序列號(hào) |
| select_type | SELECT類型,可以為以下任何一種: SIMPLE:簡(jiǎn)單SELECT(不使用UNION或子查詢) PRIMARY:最外面的SELECT UNION:UNION中的第二個(gè)或后面的SELECT語(yǔ)句 DEPENDENT UNION:UNION中的第二個(gè)或后面的SELECT語(yǔ)句,取決于外面的查詢 UNION RESULT:UNION 的結(jié)果 SUBQUERY:子查詢中的第一個(gè)SELECT DEPENDENT SUBQUERY:子查詢中的第一個(gè)SELECT,取決于外面的查詢 DERIVED:導(dǎo)出表的SELECT(FROM子句的子查詢) |
| table | 輸出的行所引用的表 |
| type | 聯(lián)接類型。下面給出各種聯(lián)接類型,按照從最佳類型到最壞類型進(jìn)行排序: system:表僅有一行(=系統(tǒng)表)。這是const聯(lián)接類型的一個(gè)特例。 const:表最多有一個(gè)匹配行,它將在查詢開(kāi)始時(shí)被讀取。因?yàn)閮H有一行,在這行的列值可被優(yōu)化器剩余部分認(rèn)為是常數(shù)。const表很快,因?yàn)樗鼈冎蛔x取一次! eq_ref:對(duì)于每個(gè)來(lái)自于前面的表的行組合,從該表中讀取一行。這可能是最好的聯(lián)接類型,除了const類型。 ref:對(duì)于每個(gè)來(lái)自于前面的表的行組合,所有有匹配索引值的行將從這張表中讀取。 ref_or_null:該聯(lián)接類型如同ref,但是添加了MySQL可以專門搜索包含NULL值的行。 index_merge:該聯(lián)接類型表示使用了索引合并優(yōu)化方法。 unique_subquery:該類型替換了下面形式的IN子查詢的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr) unique_subquery是一個(gè)索引查找函數(shù),可以完全替換子查詢,效率更高。 index_subquery:該聯(lián)接類型類似于unique_subquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr) range:只檢索給定范圍的行,使用一個(gè)索引來(lái)選擇行。 index:該聯(lián)接類型與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因?yàn)樗饕募ǔ1葦?shù)據(jù)文件小。 ALL:對(duì)于每個(gè)來(lái)自于先前的表的行組合,進(jìn)行完整的表掃描。 |
| possible_keys | 指出MySQL能使用哪個(gè)索引在該表中找到行 |
| key | 顯示MySQL實(shí)際決定使用的鍵(索引)。如果沒(méi)有選擇索引,鍵是NULL。 |
| key_len | 顯示MySQL決定使用的鍵長(zhǎng)度。如果鍵是NULL,則長(zhǎng)度為NULL。 |
| ref | 顯示使用哪個(gè)列或常數(shù)與key一起從表中選擇行。 |
| rows | 顯示MySQL認(rèn)為它執(zhí)行查詢時(shí)必須檢查的行數(shù)。多行之間的數(shù)據(jù)相乘可以估算要處理的行數(shù)。 |
| filtered | 顯示了通過(guò)條件過(guò)濾出的行數(shù)的百分比估計(jì)值。 |
| Extra | 該列包含MySQL解決查詢的詳細(xì)信息 Distinct:MySQL發(fā)現(xiàn)第1個(gè)匹配行后,停止為當(dāng)前的行組合搜索更多的行。 Not exists:MySQL能夠?qū)Σ樵冞M(jìn)行LEFT JOIN優(yōu)化,發(fā)現(xiàn)1個(gè)匹配LEFT JOIN標(biāo)準(zhǔn)的行后,不再為前面的的行組合在該表內(nèi)檢查更多的行。 range checked for each record (index map: #):MySQL沒(méi)有發(fā)現(xiàn)好的可以使用的索引,但發(fā)現(xiàn)如果來(lái)自前面的表的列值已知,可能部分索引可以使用。 Using filesort:MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。 Using index:從只使用索引樹中的信息而不需要進(jìn)一步搜索讀取實(shí)際的行來(lái)檢索表中的列信息。 Using temporary:為了解決查詢,MySQL需要?jiǎng)?chuàng)建一個(gè)臨時(shí)表來(lái)容納結(jié)果。 Using where:WHERE 子句用于限制哪一個(gè)行匹配下一個(gè)表或發(fā)送到客戶。 Using sort_union(...), Using union(...), Using intersect(...):這些函數(shù)說(shuō)明如何為index_merge聯(lián)接類型合并索引掃描。 Using index for group-by:類似于訪問(wèn)表的Using index方式,Using index for group-by表示MySQL發(fā)現(xiàn)了一個(gè)索引,可以用來(lái)查 詢GROUP BY或DISTINCT查詢的所有列,而不要額外搜索硬盤訪問(wèn)實(shí)際的表。 |
總結(jié)
以上是生活随笔為你收集整理的MySQL 之 explain的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: CentOS7 安装或迁移 wordpr
- 下一篇: rhel mysql安装_RHEL6.4