全網(wǎng)最全 | MySQL EXPLAIN 完全解讀

EXPLAIN作為MySQL的性能分析神器捌显,讀懂其結(jié)果是很有必要的笛求,然而我在各種搜索引擎上竟然找不到特別完整的解讀熬丧。都是只有重點,沒有細(xì)節(jié)(例如type的取值不全屈扎、Extra缺乏完整的介紹等)埃唯。

所以,我肝了將近一個星期鹰晨,整理了一下墨叛。這應(yīng)該是全網(wǎng)最全面、最細(xì)致的EXPLAIN解讀文章了模蜡,下面是全文漠趁。

文章比較長,建議收藏忍疾。

TIPS

本文基于MySQL 8.0編寫闯传,理論支持MySQL 5.0及更高版本。

EXPLAIN使用

explain可用來分析SQL的執(zhí)行計劃卤妒。格式如下:

{EXPLAIN | DESCRIBE | DESC}
    tbl_name [col_name | wild]

{EXPLAIN | DESCRIBE | DESC}
    [explain_type]
    {explainable_stmt | FOR CONNECTION connection_id}

{EXPLAIN | DESCRIBE | DESC} ANALYZE select_statement    

explain_type: {
    FORMAT = format_name
}

format_name: {
    TRADITIONAL
  | JSON
  | TREE
}

explainable_stmt: {
    SELECT statement
  | TABLE statement
  | DELETE statement
  | INSERT statement
  | REPLACE statement
  | UPDATE statement
}

示例:

EXPLAIN format = TRADITIONAL json SELECT tt.TicketNumber, tt.TimeIn,
               tt.ProjectReference, tt.EstimatedShipDate,
               tt.ActualShipDate, tt.ClientID,
               tt.ServiceCodes, tt.RepetitiveID,
               tt.CurrentProcess, tt.CurrentDPPerson,
               tt.RecordVolume, tt.DPPrinted, et.COUNTRY,
               et_1.COUNTRY, do.CUSTNAME
        FROM tt, et, et AS et_1, do
        WHERE tt.SubmitTime IS NULL
          AND tt.ActualPC = et.EMPLOYID
          AND tt.AssignedPC = et_1.EMPLOYID
          AND tt.ClientID = do.CUSTNMBR;

結(jié)果輸出展示:

字段 format=json時的名稱 含義
id select_id 該語句的唯一標(biāo)識
select_type 查詢類型
table table_name 表名
partitions partitions 匹配的分區(qū)
type access_type 聯(lián)接類型
possible_keys possible_keys 可能的索引選擇
key key 實際選擇的索引
key_len key_length 索引的長度
ref ref 索引的哪一列被引用了
rows rows 估計要掃描的行
filtered filtered 表示符合查詢條件的數(shù)據(jù)百分比
Extra 沒有 附加信息

結(jié)果解讀

id

該語句的唯一標(biāo)識丸边。如果explain的結(jié)果包括多個id值,則數(shù)字越大越先執(zhí)行荚孵;而對于相同id的行妹窖,則表示從上往下依次執(zhí)行。

select_type

查詢類型收叶,有如下幾種取值:

查詢類型 作用
SIMPLE 簡單查詢(未使用UNION或子查詢)
PRIMARY 最外層的查詢
UNION 在UNION中的第二個和隨后的SELECT被標(biāo)記為UNION骄呼。如果UNION被FROM子句中的子查詢包含,那么它的第一個SELECT會被標(biāo)記為DERIVED。
DEPENDENT UNION UNION中的第二個或后面的查詢蜓萄,依賴了外面的查詢
UNION RESULT UNION的結(jié)果
SUBQUERY 子查詢中的第一個 SELECT
DEPENDENT SUBQUERY 子查詢中的第一個 SELECT隅茎,依賴了外面的查詢
DERIVED 用來表示包含在FROM子句的子查詢中的SELECT,MySQL會遞歸執(zhí)行并將結(jié)果放到一個臨時表中嫉沽。MySQL內(nèi)部將其稱為是Derived table(派生表)辟犀,因為該臨時表是從子查詢派生出來的
DEPENDENT DERIVED 派生表,依賴了其他的表
MATERIALIZED 物化子查詢
UNCACHEABLE SUBQUERY 子查詢绸硕,結(jié)果無法緩存堂竟,必須針對外部查詢的每一行重新評估
UNCACHEABLE UNION UNION屬于UNCACHEABLE SUBQUERY的第二個或后面的查詢

table

表示當(dāng)前這一行正在訪問哪張表,如果SQL定義了別名玻佩,則展示表的別名

partitions

當(dāng)前查詢匹配記錄的分區(qū)出嘹。對于未分區(qū)的表,返回null

type

連接類型咬崔,有如下幾種取值税稼,性能從好到壞排序 如下:

1 system:該表只有一行(相當(dāng)于系統(tǒng)表),system是const類型的特例

2 const:針對主鍵或唯一索引的等值查詢掃描, 最多只返回一行數(shù)據(jù). const 查詢速度非晨逅梗快, 因為它僅僅讀取一次即可

3 eq_ref:當(dāng)使用了索引的全部組成部分郎仆,并且索引是PRIMARY KEY或UNIQUE NOT NULL 才會使用該類型,性能僅次于system及const兜蠕。

-- 多表關(guān)聯(lián)查詢丸升,單行匹配
SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column=other_table.column;

-- 多表關(guān)聯(lián)查詢,聯(lián)合索引牺氨,多行匹配
SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column_part1=other_table.column
  AND ref_table.key_column_part2=1;

4 ref:當(dāng)滿足索引的最左前綴規(guī)則狡耻,或者索引不是主鍵也不是唯一索引時才會發(fā)生。如果使用的索引只會匹配到少量的行猴凹,性能也是不錯的夷狰。

-- 根據(jù)索引(非主鍵,非唯一索引)郊霎,匹配到多行
SELECT * FROM ref_table WHERE key_column=expr;

-- 多表關(guān)聯(lián)查詢沼头,單個索引,多行匹配
SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column=other_table.column;

-- 多表關(guān)聯(lián)查詢书劝,聯(lián)合索引进倍,多行匹配
SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column_part1=other_table.column
  AND ref_table.key_column_part2=1;

TIPS

最左前綴原則,指的是索引按照最左優(yōu)先的方式匹配索引购对。比如創(chuàng)建了一個組合索引(column1, column2, column3)猾昆,那么,如果查詢條件是:

  • WHERE column1 = 1骡苞、WHERE column1= 1 AND column2 = 2垂蜗、WHERE column1= 1 AND column2 = 2 AND column3 = 3 都可以使用該索引楷扬;
  • WHERE column1 = 2、WHERE column1 = 1 AND column3 = 3就無法匹配該索引贴见。

5 fulltext:全文索引

6 ref_or_null:該類型類似于ref烘苹,但是MySQL會額外搜索哪些行包含了NULL。這種類型常見于解析子查詢

SELECT * FROM ref_table
  WHERE key_column=expr OR key_column IS NULL;

7 index_merge:此類型表示使用了索引合并優(yōu)化片部,表示一個查詢里面用到了多個索引

8 unique_subquery:該類型和eq_ref類似镣衡,但是使用了IN查詢,且子查詢是主鍵或者唯一索引档悠。例如:

value IN (SELECT primary_key FROM single_table WHERE some_expr)

9 index_subquery:和unique_subquery類似廊鸥,只是子查詢使用的是非唯一索引

value IN (SELECT key_column FROM single_table WHERE some_expr)

10 range:范圍掃描,表示檢索了指定范圍的行站粟,主要用于有限制的索引掃描黍图。比較常見的范圍掃描是帶有BETWEEN子句或WHERE子句里有>曾雕、>=奴烙、<、<=剖张、IS NULL切诀、<=>、BETWEEN搔弄、LIKE幅虑、IN()等操作符。

SELECT * FROM tbl_name
  WHERE key_column BETWEEN 10 and 20;

SELECT * FROM tbl_name
  WHERE key_column IN (10,20,30);

11 index:全索引掃描顾犹,和ALL類似倒庵,只不過index是全盤掃描了索引的數(shù)據(jù)。當(dāng)查詢僅使用索引中的一部分列時炫刷,可使用此類型擎宝。有兩種場景會觸發(fā):

  • 如果索引是查詢的覆蓋索引,并且索引查詢的數(shù)據(jù)就可以滿足查詢中所需的所有數(shù)據(jù)浑玛,則只掃描索引樹绍申。此時,explain的Extra 列的結(jié)果是Using index顾彰。index通常比ALL快极阅,因為索引的大小通常小于表數(shù)據(jù)。

  • 按索引的順序來查找數(shù)據(jù)行涨享,執(zhí)行了全表掃描筋搏。此時,explain的Extra列的結(jié)果不會出現(xiàn)Uses index厕隧。

  • ALL:全表掃描拆又,性能最差儒旬。

possible_keys

展示當(dāng)前查詢可以使用哪些索引,這一列的數(shù)據(jù)是在優(yōu)化過程的早期創(chuàng)建的帖族,因此有些索引可能對于后續(xù)優(yōu)化過程是沒用的栈源。

key

表示MySQL實際選擇的索引

key_len

索引使用的字節(jié)數(shù)。由于存儲格式竖般,當(dāng)字段允許為NULL時甚垦,key_len比不允許為空時大1字節(jié)。

key_len計算公式: https://www.cnblogs.com/gomysql/p/4004244.html

ref

表示將哪個字段或常量和key列所使用的字段進(jìn)行比較涣雕。

如果ref是一個函數(shù)艰亮,則使用的值是函數(shù)的結(jié)果。要想查看是哪個函數(shù)挣郭,可在EXPLAIN語句之后緊跟一個SHOW WARNING語句迄埃。

rows

MySQL估算會掃描的行數(shù),數(shù)值越小越好兑障。

filtered

表示符合查詢條件的數(shù)據(jù)百分比侄非,最大100。用rows × filtered可獲得和下一張表連接的行數(shù)流译。例如rows = 1000逞怨,filtered = 50%,則和下一張表連接的行數(shù)是500福澡。

TIPS

在MySQL 5.7之前叠赦,想要顯示此字段需使用explain extended命令;

MySQL.5.7及更高版本革砸,explain默認(rèn)就會展示filtered

Extra

展示有關(guān)本次查詢的附加信息除秀,取值如下:

1 Child of 'table' pushed join@1

此值只會在NDB Cluster下出現(xiàn)。

2 const row not found

例如查詢語句SELECT ... FROM tbl_name算利,而表是空的

3 Deleting all rows

對于DELETE語句册踩,某些引擎(例如MyISAM)支持以一種簡單而快速的方式刪除所有的數(shù)據(jù),如果使用了這種優(yōu)化笔时,則顯示此值

4 Distinct

查找distinct值棍好,當(dāng)找到第一個匹配的行后,將停止為當(dāng)前行組合搜索更多行

5 FirstMatch(tbl_name)

當(dāng)前使用了半連接FirstMatch策略允耿,詳見 https://mariadb.com/kb/en/firstmatch-strategy/ 借笙,翻譯 https://www.cnblogs.com/abclife/p/10895624.html

6 Full scan on NULL key

子查詢中的一種優(yōu)化方式,在無法通過索引訪問null值的時候使用

7 Impossible HAVING

HAVING子句始終為false较锡,不會命中任何行

8 Impossible WHERE

WHERE子句始終為false业稼,不會命中任何行

9 Impossible WHERE noticed after reading const tables

MySQL已經(jīng)讀取了所有const(或system)表,并發(fā)現(xiàn)WHERE子句始終為false

10 LooseScan(m..n)

當(dāng)前使用了半連接LooseScan策略蚂蕴,詳見 https://mariadb.com/kb/en/loosescan-strategy/ 低散,翻譯 http://www.javacoder.cn/?p=39

11 No matching min/max row

沒有任何能滿足例如 SELECT MIN(...) FROM ... WHERE condition 中的condition的行

12 no matching row in const table

對于關(guān)聯(lián)查詢俯邓,存在一個空表,或者沒有行能夠滿足唯一索引條件

13 No matching rows after partition pruning

對于DELETE或UPDATE語句熔号,優(yōu)化器在partition pruning(分區(qū)修剪)之后稽鞭,找不到要delete或update的內(nèi)容

14 No tables used

當(dāng)此查詢沒有FROM子句或擁有FROM DUAL子句時出現(xiàn)。例如:explain select 1

15 Not exists

MySQL能對LEFT JOIN優(yōu)化引镊,在找到符合LEFT JOIN的行后朦蕴,不會為上一行組合中檢查此表中的更多行。例如:

SELECT * FROM t1 LEFT JOIN t2 ON t1.id=t2.id
  WHERE t2.id IS NULL;

假設(shè)t2.id定義成了NOT NULL 弟头,此時吩抓,MySQL會掃描t1,并使用t1.id的值查找t2中的行赴恨。 如果MySQL在t2中找到一個匹配的行疹娶,它會知道t2.id永遠(yuǎn)不會為NULL,并且不會掃描t2中具有相同id值的其余行伦连。也就是說雨饺,對于t1中的每一行,MySQL只需要在t2中只執(zhí)行一次查找除师,而不考慮在t2中實際匹配的行數(shù)沛膳。

在MySQL 8.0.17及更高版本中扔枫,如果出現(xiàn)此提示汛聚,還可表示形如 NOT IN (subquery) 或 NOT EXISTS (subquery) 的WHERE條件已經(jīng)在內(nèi)部轉(zhuǎn)換為反連接。這將刪除子查詢并將其表放入最頂層的查詢計劃中短荐,從而改進(jìn)查詢的開銷倚舀。通過合并半連接和反聯(lián)接,優(yōu)化器可以更加自由地對執(zhí)行計劃中的表重新排序忍宋,在某些情況下痕貌,可讓查詢提速。你可以通過在EXPLAIN語句后緊跟一個SHOW WARNING語句糠排,并分析結(jié)果中的Message列舵稠,從而查看何時對該查詢執(zhí)行了反聯(lián)接轉(zhuǎn)換。

Note

兩表關(guān)聯(lián)只返回主表的數(shù)據(jù)入宦,并且只返回主表與子表沒關(guān)聯(lián)上的數(shù)據(jù)哺徊,這種連接就叫反連接

16 Plan isn't ready yet

使用了EXPLAIN FOR CONNECTION,當(dāng)優(yōu)化器尚未完成為在指定連接中為執(zhí)行的語句創(chuàng)建執(zhí)行計劃時乾闰, 就會出現(xiàn)此值落追。

17 Range checked for each record (index map: N)

MySQL沒有找到合適的索引去使用,但是去檢查是否可以使用range或index_merge來檢索行時涯肩,會出現(xiàn)此提示轿钠。index map N索引的編號從1開始巢钓,按照與表的SHOW INDEX所示相同的順序。 索引映射值N是指示哪些索引是候選的位掩碼值疗垛。 例如0x19(二進(jìn)制11001)的值意味著將考慮索引1症汹、4和5。

示例:下面例子中贷腕,name是varchar類型烈菌,但是條件給出整數(shù)型,涉及到隱式轉(zhuǎn)換花履。
圖中t2也沒有用到索引芽世,是因為查詢之前我將t2中name字段排序規(guī)則改為utf8_bin導(dǎo)致的鏈接字段排序規(guī)則不匹配。

explain select a.* from t1 a left  join t2 b
on t1.name = t2.name
where t2.name = 2;

結(jié)果:

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t2 NULL ALL idx_name NULL NULL NULL 9 11.11 Using where
1 SIMPLE t1 NULL ALL idx_name NULL NULL NULL 5 11.11 Range checked for each record (index map: 0x8)

18 Recursive

出現(xiàn)了遞歸查詢诡壁。詳見 “WITH (Common Table Expressions)”

19 Rematerialize

用得很少济瓢,使用類似如下SQL時,會展示Rematerialize

SELECT
  ...
FROM
  t,
  LATERAL (derived table that refers to t) AS dt
...

20 Scanned N databases

表示在處理INFORMATION_SCHEMA表的查詢時妹卿,掃描了幾個目錄旺矾,N的取值可以是0,1或者all夺克。詳見 “Optimizing INFORMATION_SCHEMA Queries”

21 Select tables optimized away

優(yōu)化器確定:①最多返回1行箕宙;②要產(chǎn)生該行的數(shù)據(jù),要讀取一組確定的行铺纽,時會出現(xiàn)此提示柬帕。一般在用某些聚合函數(shù)訪問存在索引的某個字段時,優(yōu)化器會通過索引直接一次定位到所需要的數(shù)據(jù)行完成整個查詢時展示狡门,例如下面這條SQL陷寝。

explain
select min(id)
from t1;

22 Skip_open_table, Open_frm_only其馏, Open_full_table

這些值表示適用于INFORMATION_SCHEMA表查詢的文件打開優(yōu)化凤跑;

23 Skip_open_table:無需打開表文件,信息已經(jīng)通過掃描數(shù)據(jù)字典獲得

24 Open_frm_only:僅需要讀取數(shù)據(jù)字典以獲取表信息

25 Open_full_table:未優(yōu)化的信息查找叛复。表信息必須從數(shù)據(jù)字典以及表文件中讀取

26 Start temporary, End temporary

表示臨時表使用Duplicate Weedout策略仔引,詳見 https://mariadb.com/kb/en/duplicateweedout-strategy/ ,翻譯 https://www.cnblogs.com/abclife/p/10895531.html

27 unique row not found

對于形如 SELECT ... FROM tbl_name 的查詢褐奥,但沒有行能夠滿足唯一索引或主鍵查詢的條件

28 Using filesort

當(dāng)Query 中包含 ORDER BY 操作咖耘,而且無法利用索引完成排序操作的時候,MySQL Query Optimizer 不得不選擇相應(yīng)的排序算法來實現(xiàn)抖僵。數(shù)據(jù)較少時從內(nèi)存排序鲤看,否則從磁盤排序。Explain不會顯示的告訴客戶端用哪種排序耍群。官方解釋:“MySQL需要額外的一次傳遞义桂,以找出如何按排序順序檢索行找筝。通過根據(jù)聯(lián)接類型瀏覽所有行并為所有匹配WHERE子句的行保存排序關(guān)鍵字和行的指針來完成排序。然后關(guān)鍵字被排序慷吊,并按排序順序檢索行”

29 Using index

僅使用索引樹中的信息從表中檢索列信息袖裕,而不必進(jìn)行其他查找以讀取實際行。當(dāng)查詢僅使用屬于單個索引的列時溉瓶,可以使用此策略急鳄。例如:

explain SELECT id FROM t

30 Using index condition

表示先按條件過濾索引,過濾完索引后找到所有符合索引條件的數(shù)據(jù)行堰酿,隨后用 WHERE 子句中的其他條件去過濾這些數(shù)據(jù)行疾宏。通過這種方式,除非有必要触创,否則索引信息將可以延遲“下推”讀取整個行的數(shù)據(jù)坎藐。詳見 “Index Condition Pushdown Optimization” 。例如:

TIPS

  • MySQL分成了Server層和引擎層哼绑,下推指的是將請求交給引擎層處理岩馍。

  • 理解這個功能,可創(chuàng)建所以INDEX (zipcode, lastname, firstname)抖韩,并分別用如下指令蛀恩,

    SET optimizer_switch = 'index_condition_pushdown=off'; 
    SET optimizer_switch = 'index_condition_pushdown=on';
    

    開或者關(guān)閉索引條件下推,并對比:

    explain SELECT * FROM people
      WHERE zipcode='95054'
      AND lastname LIKE '%etrunia%'
      AND address LIKE '%Main Street%';
    

    的執(zhí)行結(jié)果茂浮。

  • index condition pushdown從MySQL 5.6開始支持双谆,是MySQL針對特定場景的優(yōu)化機(jī)制,感興趣的可以看下 https://blog.51cto.com/lee90/2060449

31 Using index for group-by

數(shù)據(jù)訪問和 Using index 一樣励稳,所需數(shù)據(jù)只須要讀取索引佃乘,當(dāng)Query 中使用GROUP BY或DISTINCT 子句時囱井,如果分組字段也在索引中驹尼,Extra中的信息就會是 Using index for group-by。詳見 “GROUP BY Optimization”

-- name字段有索引
explain SELECT name FROM t1 group by name

32 Using index for skip scan

表示使用了Skip Scan庞呕。詳見 Skip Scan Range Access Method

33 Using join buffer (Block Nested Loop), Using join buffer (Batched Key Access)

使用Block Nested Loop或Batched Key Access算法提高join的性能新翎。詳見 https://www.cnblogs.com/chenpingzhao/p/6720531.html

34 Using MRR

使用了Multi-Range Read優(yōu)化策略。詳見 “Multi-Range Read Optimization”

35 Using sort_union(...), Using union(...), Using intersect(...)

這些指示索引掃描如何合并為index_merge連接類型住练。詳見 “Index Merge Optimization” 地啰。

36 Using temporary

為了解決該查詢,MySQL需要創(chuàng)建一個臨時表來保存結(jié)果讲逛。如果查詢包含不同列的GROUP BY和 ORDER BY子句亏吝,通常會發(fā)生這種情況。

-- name無索引
explain SELECT name FROM t1 group by name

37 Using where

如果我們不是讀取表的所有數(shù)據(jù)盏混,或者不是僅僅通過索引就可以獲取所有需要的數(shù)據(jù)蔚鸥,則會出現(xiàn)using where信息

explain SELECT * FROM t1 where id > 5

38 Using where with pushed condition

僅用于NDB

39 Zero limit

該查詢有一個limit 0子句惜论,不能選擇任何行

explain SELECT name FROM resource_template limit 0

擴(kuò)展的EXPLAIN

EXPLAIN可產(chǎn)生額外的擴(kuò)展信息,可通過在EXPLAIN語句后緊跟一條SHOW WARNING語句查看擴(kuò)展信息止喷。

TIPS

  • 在MySQL 8.0.12及更高版本馆类,擴(kuò)展信息可用于SELECT、DELETE弹谁、INSERT乾巧、REPLACE、UPDATE語句预愤;在MySQL 8.0.12之前沟于,擴(kuò)展信息僅適用于SELECT語句;
  • 在MySQL 5.6及更低版本植康,需使用EXPLAIN EXTENDED xxx語句社裆;而從MySQL 5.7開始,無需添加EXTENDED關(guān)鍵詞向图。

使用示例:

mysql> EXPLAIN
       SELECT t1.a, t1.a IN (SELECT t2.a FROM t2) FROM t1\G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: t1
         type: index
possible_keys: NULL
          key: PRIMARY
      key_len: 4
          ref: NULL
         rows: 4
     filtered: 100.00
        Extra: Using index
*************************** 2. row ***************************
           id: 2
  select_type: SUBQUERY
        table: t2
         type: index
possible_keys: a
          key: a
      key_len: 5
          ref: NULL
         rows: 3
     filtered: 100.00
        Extra: Using index
2 rows in set, 1 warning (0.00 sec)

mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
  Level: Note
   Code: 1003
Message: /* select#1 */ select `test`.`t1`.`a` AS `a`,
         <in_optimizer>(`test`.`t1`.`a`,`test`.`t1`.`a` in
         ( <materialize> (/* select#2 */ select `test`.`t2`.`a`
         from `test`.`t2` where 1 having 1 ),
         <primary_index_lookup>(`test`.`t1`.`a` in
         <temporary table> on <auto_key>
         where ((`test`.`t1`.`a` = `materialized-subquery`.`a`))))) AS `t1.a
         IN (SELECT t2.a FROM t2)` from `test`.`t1`
1 row in set (0.00 sec)

由于SHOW WARNING的結(jié)果并不一定是一個有效SQL泳秀,也不一定能夠執(zhí)行(因為里面包含了很多特殊標(biāo)記)。特殊標(biāo)記取值如下:

1 <auto_key>

自動生成的臨時表key

2 <cache>(expr)

表達(dá)式(例如標(biāo)量子查詢)執(zhí)行了一次榄攀,并且將值保存在了內(nèi)存中以備以后使用嗜傅。對于包括多個值的結(jié)果,可能會創(chuàng)建臨時表檩赢,你將會看到 <temporary table> 的字樣

3 <exists>(query fragment)

子查詢被轉(zhuǎn)換為 EXISTS

4 <in_optimizer>(query fragment)

這是一個內(nèi)部優(yōu)化器對象吕嘀,對用戶沒有任何意義

5 <index_lookup>(query fragment)

使用索引查找來處理查詢片段,從而找到合格的行

6 <if>(condition, expr1, expr2)

如果條件是true贞瞒,則取expr1偶房,否則取expr2

7 <is_not_null_test>(expr)

驗證表達(dá)式不為NULL的測試

8 <materialize>(query fragment)

使用子查詢實現(xiàn)

9 materialized-subquery.col_name

在內(nèi)部物化臨時表中對col_name的引用,以保存子查詢的結(jié)果

10 <primary_index_lookup>(query fragment)

使用主鍵來處理查詢片段军浆,從而找到合格的行

11 <ref_null_helper>(expr)

這是一個內(nèi)部優(yōu)化器對象棕洋,對用戶沒有任何意義

12 /* select#N */ select_stmt

SELECT與非擴(kuò)展的EXPLAIN輸出中id=N的那行關(guān)聯(lián)

13 outer_tables semi join (inner_tables)

半連接操作。inner_tables展示未拉出的表乒融。詳見 “Optimizing Subqueries, Derived Tables, and View References with Semijoin Transformations”

14 <temporary table>

表示創(chuàng)建了內(nèi)部臨時表而緩存中間結(jié)果

當(dāng)某些表是const或system類型時掰盘,這些表中的列所涉及的表達(dá)式將由優(yōu)化器盡早評估,并且不屬于所顯示語句的一部分赞季。但是愧捕,當(dāng)使用FORMAT=JSON時,某些const表的訪問將顯示為ref申钩。

估計查詢性能

多數(shù)情況下次绘,你可以通過計算磁盤的搜索次數(shù)來估算查詢性能。對于比較小的表,通秤寿耍可以在一次磁盤搜索中找到行(因為索引可能已經(jīng)被緩存了)罗洗,而對于更大的表,你可以使用B-tree索引進(jìn)行估算:你需要進(jìn)行多少次查找才能找到行:log(row_count) / log(index_block_length / 3 * 2 / (index_length + data_pointer_length)) + 1

在MySQL中钢猛,index_block_length通常是1024字節(jié)伙菜,數(shù)據(jù)指針一般是4字節(jié)。比方說命迈,有一個500,000的表贩绕,key是3字節(jié),那么根據(jù)計算公式 log(500,000)/log(1024/3*2/(3+4)) + 1 = 4 次搜索壶愤。

該索引將需要500,000 * 7 * 3/2 = 5.2MB的存儲空間(假設(shè)典型的索引緩存的填充率是2/3)淑倾,因此你可以在內(nèi)存中存放更多索引,可能只要一到兩個調(diào)用就可以找到想要的行了征椒。

但是娇哆,對于寫操作,你需要四個搜索請求來查找在何處放置新的索引值勃救,然后通常需要2次搜索來更新索引并寫入行碍讨。

前面的討論并不意味著你的應(yīng)用性能會因為log N而緩慢下降。只要內(nèi)容被OS或MySQL服務(wù)器緩存蒙秒,隨著表的變大勃黍,只會稍微變慢。在數(shù)據(jù)量變得太大而無法緩存后晕讲,將會變慢很多覆获,直到你的應(yīng)用程序受到磁盤搜索約束(按照log N增長)。為了避免這種情況瓢省,可以根據(jù)數(shù)據(jù)的增長而增加key的弄息。對于MyISAM表,key的緩存大小由名為key_buffer_size的系統(tǒng)變量控制勤婚,詳見 Section 5.1.1, “Configuring the Server”

參考文檔

本文首發(fā)

http://www.itmuch.com/mysql/explain 轉(zhuǎn)載請注明出處蛔六。

本文由博客一文多發(fā)平臺 OpenWrite 發(fā)布荆永!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市誓篱,隨后出現(xiàn)的幾起案子呼巴,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绢涡,死亡現(xiàn)場離奇詭異以蕴,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門宁玫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人柑晒,你說我怎么就攤上這事欧瘪。” “怎么了匙赞?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵佛掖,是天一觀的道長。 經(jīng)常有香客問我涌庭,道長芥被,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任坐榆,我火速辦了婚禮拴魄,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘席镀。我一直安慰自己匹中,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布豪诲。 她就那樣靜靜地躺著职员,像睡著了一般。 火紅的嫁衣襯著肌膚如雪跛溉。 梳的紋絲不亂的頭發(fā)上焊切,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天,我揣著相機(jī)與錄音芳室,去河邊找鬼专肪。 笑死,一個胖子當(dāng)著我的面吹牛堪侯,可吹牛的內(nèi)容都是我干的嚎尤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼伍宦,長吁一口氣:“原來是場噩夢啊……” “哼芽死!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起次洼,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤关贵,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后卖毁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體揖曾,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了炭剪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片练链。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖奴拦,靈堂內(nèi)的尸體忽然破棺而出媒鼓,到底是詐尸還是另有隱情,我是刑警寧澤错妖,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布绿鸣,位于F島的核電站,受9級特大地震影響站玄,放射性物質(zhì)發(fā)生泄漏枚驻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一株旷、第九天 我趴在偏房一處隱蔽的房頂上張望再登。 院中可真熱鬧,春花似錦晾剖、人聲如沸锉矢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽沽损。三九已至,卻和暖如春循头,著一層夾襖步出監(jiān)牢的瞬間绵估,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工卡骂, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留国裳,地道東北人。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓全跨,卻偏偏與公主長得像缝左,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子浓若,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,864評論 2 354