MySQL EXPLAIN 完全解讀【轉(zhuǎn)】

轉(zhuǎn)自:https://www.imooc.com/article/308225

EXPLAIN作為MySQL的性能分析神器懦胞,讀懂其結(jié)果是很有必要的惦积,然而我在各種搜索引擎上竟然找不到特別完整的解讀障癌。都是只有重點(diǎn)幸海,沒(méi)有細(xì)節(jié)(例如type的取值不全、Extra缺乏完整的介紹等)菩帝。

所以刊棕,我肝了將近一個(gè)星期,整理了一下伙菜。這應(yīng)該是全網(wǎng)最全面轩缤、最細(xì)致的EXPLAIN解讀文章了命迈,下面是全文。

文章比較長(zhǎng)火的,建議收藏壶愤。

TIPS

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

EXPLAIN使用

explain可用來(lái)分析SQL的執(zhí)行計(jì)劃征椒。格式如下:

{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時(shí)的名稱 含義
id select_id 該語(yǔ)句的唯一標(biāo)識(shí)
select_type 無(wú) 查詢類型
table table_name 表名
partitions partitions 匹配的分區(qū)
type access_type 聯(lián)接類型
possible_keys possible_keys 可能的索引選擇
key key 實(shí)際選擇的索引
key_len key_length 索引的長(zhǎng)度
ref ref 索引的哪一列被引用了
rows rows 估計(jì)要掃描的行
filtered filtered 表示符合查詢條件的數(shù)據(jù)百分比
Extra 沒(méi)有 附加信息

結(jié)果解讀

id

該語(yǔ)句的唯一標(biāo)識(shí)。如果explain的結(jié)果包括多個(gè)id值湃累,則數(shù)字越大越先執(zhí)行勃救;而對(duì)于相同id的行,則表示從上往下依次執(zhí)行治力。

select_type

查詢類型蒙秒,有如下幾種取值:

查詢類型 作用
SIMPLE 簡(jiǎn)單查詢(未使用UNION或子查詢)
PRIMARY 最外層的查詢
UNION 在UNION中的第二個(gè)和隨后的SELECT被標(biāo)記為UNION。如果UNION被FROM子句中的子查詢包含宵统,那么它的第一個(gè)SELECT會(huì)被標(biāo)記為DERIVED晕讲。
DEPENDENT UNION UNION中的第二個(gè)或后面的查詢,依賴了外面的查詢
UNION RESULT UNION的結(jié)果
SUBQUERY 子查詢中的第一個(gè) SELECT
DEPENDENT SUBQUERY 子查詢中的第一個(gè) SELECT马澈,依賴了外面的查詢
DERIVED 用來(lái)表示包含在FROM子句的子查詢中的SELECT瓢省,MySQL會(huì)遞歸執(zhí)行并將結(jié)果放到一個(gè)臨時(shí)表中。MySQL內(nèi)部將其稱為是Derived table(派生表)痊班,因?yàn)樵撆R時(shí)表是從子查詢派生出來(lái)的
DEPENDENT DERIVED 派生表勤婚,依賴了其他的表
MATERIALIZED 物化子查詢
UNCACHEABLE SUBQUERY 子查詢,結(jié)果無(wú)法緩存涤伐,必須針對(duì)外部查詢的每一行重新評(píng)估
UNCACHEABLE UNION UNION屬于UNCACHEABLE SUBQUERY的第二個(gè)或后面的查詢

table

表示當(dāng)前這一行正在訪問(wèn)哪張表馒胆,如果SQL定義了別名荆永,則展示表的別名

partitions

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

type

連接類型具钥,有如下幾種取值,性能從好到壞排序 如下:

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

  • const:針對(duì)主鍵或唯一索引的等值查詢掃描, 最多只返回一行數(shù)據(jù). const 查詢速度非陈钌荆快, 因?yàn)樗鼉H僅讀取一次即可

  • eq_ref:當(dāng)使用了索引的全部組成部分,并且索引是PRIMARY KEY或UNIQUE NOT NULL 才會(huì)使用該類型四啰,性能僅次于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;
    
    
  • ref:當(dāng)滿足索引的最左前綴規(guī)則,或者索引不是主鍵也不是唯一索引時(shí)才會(huì)發(fā)生匙赞。如果使用的索引只會(huì)匹配到少量的行佛掖,性能也是不錯(cuò)的。

    -- 根據(jù)索引(非主鍵涌庭,非唯一索引)芥被,匹配到多行
    SELECT * FROM ref_table WHERE key_column=expr;
    
    -- 多表關(guān)聯(lián)查詢,單個(gè)索引坐榆,多行匹配
    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)建了一個(gè)組合索引(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就無(wú)法匹配該索引。
  • fulltext:全文索引

  • ref_or_null:該類型類似于ref芳室,但是MySQL會(huì)額外搜索哪些行包含了NULL专肪。這種類型常見于解析子查詢

    SELECT * FROM ref_table
      WHERE key_column=expr OR key_column IS NULL;
    
    
  • index_merge:此類型表示使用了索引合并優(yōu)化,表示一個(gè)查詢里面用到了多個(gè)索引

  • unique_subquery:該類型和eq_ref類似堪侯,但是使用了IN查詢嚎尤,且子查詢是主鍵或者唯一索引。例如:

    value IN (SELECT primary_key FROM single_table WHERE some_expr)
    
    
  • index_subquery:和unique_subquery類似伍宦,只是子查詢使用的是非唯一索引

    value IN (SELECT key_column FROM single_table WHERE some_expr)
    
    
  • 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);
    
    
  • index:全索引掃描奴拦,和ALL類似媒鼓,只不過(guò)index是全盤掃描了索引的數(shù)據(jù)。當(dāng)查詢僅使用索引中的一部分列時(shí)错妖,可使用此類型绿鸣。有兩種場(chǎng)景會(huì)觸發(fā):

    • 如果索引是查詢的覆蓋索引,并且索引查詢的數(shù)據(jù)就可以滿足查詢中所需的所有數(shù)據(jù)站玄,則只掃描索引樹枚驻。此時(shí)濒旦,explain的Extra 列的結(jié)果是Using index株旷。index通常比ALL快,因?yàn)樗饕拇笮⊥ǔP∮诒頂?shù)據(jù)尔邓。
    • 按索引的順序來(lái)查找數(shù)據(jù)行晾剖,執(zhí)行了全表掃描。此時(shí)梯嗽,explain的Extra列的結(jié)果不會(huì)出現(xiàn)Uses index齿尽。
  • ALL:全表掃描,性能最差灯节。

possible_keys

展示當(dāng)前查詢可以使用哪些索引循头,這一列的數(shù)據(jù)是在優(yōu)化過(guò)程的早期創(chuàng)建的,因此有些索引可能對(duì)于后續(xù)優(yōu)化過(guò)程是沒(méi)用的炎疆。

key

表示MySQL實(shí)際選擇的索引

key_len

索引使用的字節(jié)數(shù)卡骂。由于存儲(chǔ)格式,當(dāng)字段允許為NULL時(shí)形入,key_len比不允許為空時(shí)大1字節(jié)全跨。

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

ref

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

如果ref是一個(gè)函數(shù)亿遂,則使用的值是函數(shù)的結(jié)果浓若。要想查看是哪個(gè)函數(shù)渺杉,可在EXPLAIN語(yǔ)句之后緊跟一個(gè)SHOW WARNING語(yǔ)句。

rows

MySQL估算會(huì)掃描的行數(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)就會(huì)展示filtered

Extra

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

  • Child of ‘table’ pushed join@1

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

  • const row not found

    例如查詢語(yǔ)句SELECT … FROM tbl_name敷燎,而表是空的

  • Deleting all rows

    對(duì)于DELETE語(yǔ)句,某些引擎(例如MyISAM)支持以一種簡(jiǎn)單而快速的方式刪除所有的數(shù)據(jù)箩言,如果使用了這種優(yōu)化硬贯,則顯示此值

  • Distinct

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

  • FirstMatch(tbl_name)

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

  • Full scan on NULL key

    子查詢中的一種優(yōu)化方式务漩,在無(wú)法通過(guò)索引訪問(wèn)null值的時(shí)候使用

  • Impossible HAVING

    HAVING子句始終為false拄衰,不會(huì)命中任何行

  • Impossible WHERE

    WHERE子句始終為false,不會(huì)命中任何行

  • Impossible WHERE noticed after reading const tables

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

  • LooseScan(m…n)

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

  • No matching min/max row

    沒(méi)有任何能滿足例如 SELECT MIN(…) FROM … WHERE condition 中的condition的行

  • no matching row in const table

    對(duì)于關(guān)聯(lián)查詢居触,存在一個(gè)空表妖混,或者沒(méi)有行能夠滿足唯一索引條件

  • No matching rows after partition pruning

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

  • No tables used

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

  • Not exists

    MySQL能對(duì)LEFT JOIN優(yōu)化,在找到符合LEFT JOIN的行后砖瞧,不會(huì)為上一行組合中檢查此表中的更多行息堂。例如:

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

    假設(shè)t2.id定義成了NOT NULL ,此時(shí),MySQL會(huì)掃描t1荣堰,并使用t1.id的值查找t2中的行床未。 如果MySQL在t2中找到一個(gè)匹配的行,它會(huì)知道t2.id永遠(yuǎn)不會(huì)為NULL振坚,并且不會(huì)掃描t2中具有相同id值的其余行薇搁。也就是說(shuō),對(duì)于t1中的每一行渡八,MySQL只需要在t2中只執(zhí)行一次查找啃洋,而不考慮在t2中實(shí)際匹配的行數(shù)。

    在MySQL 8.0.17及更高版本中屎鳍,如果出現(xiàn)此提示宏娄,還可表示形如 NOT IN (subquery) 或 NOT EXISTS (subquery) 的WHERE條件已經(jīng)在內(nèi)部轉(zhuǎn)換為反連接。這將刪除子查詢并將其表放入最頂層的查詢計(jì)劃中逮壁,從而改進(jìn)查詢的開銷孵坚。通過(guò)合并半連接和反聯(lián)接,優(yōu)化器可以更加自由地對(duì)執(zhí)行計(jì)劃中的表重新排序窥淆,在某些情況下卖宠,可讓查詢提速。你可以通過(guò)在EXPLAIN語(yǔ)句后緊跟一個(gè)SHOW WARNING語(yǔ)句忧饭,并分析結(jié)果中的Message列扛伍,從而查看何時(shí)對(duì)該查詢執(zhí)行了反聯(lián)接轉(zhuǎn)換。

    Note

    兩表關(guān)聯(lián)只返回主表的數(shù)據(jù)词裤,并且只返回主表與子表沒(méi)關(guān)聯(lián)上的數(shù)據(jù)刺洒,這種連接就叫反連接

  • Plan isn’t ready yet

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

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

    MySQL沒(méi)有找到合適的索引去使用,但是去檢查是否可以使用range或index_merge來(lái)檢索行時(shí)帅刊,會(huì)出現(xiàn)此提示。index map N索引的編號(hào)從1開始漂问,按照與表的SHOW INDEX所示相同的順序赖瞒。 索引映射值N是指示哪些索引是候選的位掩碼值。 例如0x19(二進(jìn)制11001)的值意味著將考慮索引1蚤假、4和5栏饮。

    示例:下面例子中,name是varchar類型磷仰,但是條件給出整數(shù)型袍嬉,涉及到隱式轉(zhuǎn)換。
    圖中t2也沒(méi)有用到索引,是因?yàn)椴樵冎拔覍2中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)
  • Recursive

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

  • Rematerialize

    用得很少,使用類似如下SQL時(shí)罐监,會(huì)展示Rematerialize

    SELECT
      ...
    FROM
      t,
      LATERAL (derived table that refers to t) AS dt
    ...
    
    
  • Scanned N databases

    表示在處理INFORMATION_SCHEMA表的查詢時(shí)吴藻,掃描了幾個(gè)目錄,N的取值可以是0弓柱,1或者all沟堡。詳見 “Optimizing INFORMATION_SCHEMA Queries”

  • Select tables optimized away

    優(yōu)化器確定:①最多返回1行;②要產(chǎn)生該行的數(shù)據(jù)矢空,要讀取一組確定的行航罗,時(shí)會(huì)出現(xiàn)此提示。一般在用某些聚合函數(shù)訪問(wèn)存在索引的某個(gè)字段時(shí)屁药,優(yōu)化器會(huì)通過(guò)索引直接一次定位到所需要的數(shù)據(jù)行完成整個(gè)查詢時(shí)展示伤哺,例如下面這條SQL。

    explain
    select min(id)
    from t1;
    
    
  • Skip_open_table者祖, Open_frm_only立莉, Open_full_table

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

    • Skip_open_table:無(wú)需打開表文件七问,信息已經(jīng)通過(guò)掃描數(shù)據(jù)字典獲得
    • Open_frm_only:僅需要讀取數(shù)據(jù)字典以獲取表信息
    • Open_full_table:未優(yōu)化的信息查找蜓耻。表信息必須從數(shù)據(jù)字典以及表文件中讀取
  • Start temporary, End temporary

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

  • unique row not found

    對(duì)于形如 SELECT … FROM tbl_name 的查詢刹淌,但沒(méi)有行能夠滿足唯一索引或主鍵查詢的條件

  • Using filesort

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

  • Using index

    僅使用索引樹中的信息從表中檢索列信息茁裙,而不必進(jìn)行其他查找以讀取實(shí)際行塘砸。當(dāng)查詢僅使用屬于單個(gè)索引的列時(shí),可以使用此策略晤锥。例如:

    explain SELECT id FROM t
    
    
  • Using index condition

    表示先按條件過(guò)濾索引掉蔬,過(guò)濾完索引后找到所有符合索引條件的數(shù)據(jù)行廊宪,隨后用 WHERE 子句中的其他條件去過(guò)濾這些數(shù)據(jù)行。通過(guò)這種方式女轿,除非有必要箭启,否則索引信息將可以延遲“下推”讀取整個(gè)行的數(shù)據(jù)。詳見 “Index Condition Pushdown Optimization” 谈喳。例如:

    TIPS

    • MySQL分成了Server層和引擎層册烈,下推指的是將請(qǐng)求交給引擎層處理。
    • 理解這個(gè)功能婿禽,可創(chuàng)建所以INDEX (zipcode, lastname, firstname)赏僧,并分別用如下指令,
    ```
    SET optimizer_switch = 'index_condition_pushdown=off'; 
    SET optimizer_switch = 'index_condition_pushdown=on';
    
    ```
    
    
    
    開或者關(guān)閉索引條件下推扭倾,并對(duì)比:
    
    
    
    ```
    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針對(duì)特定場(chǎng)景的優(yōu)化機(jī)制膛壹,感興趣的可以看下 https://blog.51cto.com/lee90/2060449
  • Using index for group-by

    數(shù)據(jù)訪問(wèn)和 Using index 一樣驾中,所需數(shù)據(jù)只須要讀取索引,當(dāng)Query 中使用GROUP BY或DISTINCT 子句時(shí)模聋,如果分組字段也在索引中肩民,Extra中的信息就會(huì)是 Using index for group-by。詳見 “GROUP BY Optimization”

    -- name字段有索引
    explain SELECT name FROM t1 group by name
    
    
  • Using index for skip scan

    表示使用了Skip Scan链方。詳見 Skip Scan Range Access Method

  • 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

  • Using MRR

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

  • Using sort_union(…), Using union(…), Using intersect(…)

    這些指示索引掃描如何合并為index_merge連接類型祟蚀。詳見 “Index Merge Optimization” 工窍。

  • Using temporary

    為了解決該查詢,MySQL需要?jiǎng)?chuàng)建一個(gè)臨時(shí)表來(lái)保存結(jié)果前酿。如果查詢包含不同列的GROUP BY和 ORDER BY子句患雏,通常會(huì)發(fā)生這種情況。

    -- name無(wú)索引
    explain SELECT name FROM t1 group by name
    
    
  • Using where

    如果我們不是讀取表的所有數(shù)據(jù)罢维,或者不是僅僅通過(guò)索引就可以獲取所有需要的數(shù)據(jù)淹仑,則會(huì)出現(xiàn)using where信息

    explain SELECT * FROM t1 where id > 5
    
    
  • Using where with pushed condition

    僅用于NDB

  • Zero limit

    該查詢有一個(gè)limit 0子句,不能選擇任何行

    explain SELECT name FROM resource_template limit 0
    
    

擴(kuò)展的EXPLAIN

EXPLAIN可產(chǎn)生額外的擴(kuò)展信息言津,可通過(guò)在EXPLAIN語(yǔ)句后緊跟一條SHOW WARNING語(yǔ)句查看擴(kuò)展信息攻人。

TIPS

  • 在MySQL 8.0.12及更高版本,擴(kuò)展信息可用于SELECT悬槽、DELETE、INSERT瞬浓、REPLACE初婆、UPDATE語(yǔ)句;在MySQL 8.0.12之前,擴(kuò)展信息僅適用于SELECT語(yǔ)句磅叛;
  • 在MySQL 5.6及更低版本屑咳,需使用EXPLAIN EXTENDED xxx語(yǔ)句;而從MySQL 5.7開始弊琴,無(wú)需添加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é)果并不一定是一個(gè)有效SQL,也不一定能夠執(zhí)行(因?yàn)槔锩姘撕芏嗵厥鈽?biāo)記)敲董。特殊標(biāo)記取值如下:

  • <auto_key>

    自動(dòng)生成的臨時(shí)表key

  • <cache>(expr)

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

  • <exists>(query fragment)

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

  • <in_optimizer>(query fragment)

    這是一個(gè)內(nèi)部?jī)?yōu)化器對(duì)象,對(duì)用戶沒(méi)有任何意義

  • <index_lookup>(query fragment)

    使用索引查找來(lái)處理查詢片段萄窜,從而找到合格的行

  • <if>(condition, expr1, expr2)

    如果條件是true铃剔,則取expr1,否則取expr2

  • <is_not_null_test>(expr)

    驗(yàn)證表達(dá)式不為NULL的測(cè)試

  • <materialize>(query fragment)

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

  • materialized-subquery.col_name

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

  • <primary_index_lookup>(query fragment)

    使用主鍵來(lái)處理查詢片段键兜,從而找到合格的行

  • <ref_null_helper>(expr)

    這是一個(gè)內(nèi)部?jī)?yōu)化器對(duì)象,對(duì)用戶沒(méi)有任何意義

  • /* select#N */ select_stmt

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

  • outer_tables semi join (inner_tables)

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

  • <temporary table>

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

當(dāng)某些表是const或system類型時(shí),這些表中的列所涉及的表達(dá)式將由優(yōu)化器盡早評(píng)估火欧,并且不屬于所顯示語(yǔ)句的一部分棋电。但是,當(dāng)使用FORMAT=JSON時(shí)苇侵,某些const表的訪問(wèn)將顯示為ref赶盔。

估計(jì)查詢性能

多數(shù)情況下,你可以通過(guò)計(jì)算磁盤的搜索次數(shù)來(lái)估算查詢性能榆浓。對(duì)于比較小的表于未,通常可以在一次磁盤搜索中找到行(因?yàn)樗饕赡芤呀?jīng)被緩存了)陡鹃,而對(duì)于更大的表烘浦,你可以使用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é)闷叉。比方說(shuō),有一個(gè)500,000的表脊阴,key是3字節(jié)握侧,那么根據(jù)計(jì)算公式 log(500,000)/log(1024/3*2/(3+4)) + 1 = 4 次搜索蚯瞧。

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

但是,對(duì)于寫操作萄传,你需要四個(gè)搜索請(qǐng)求來(lái)查找在何處放置新的索引值甚颂,然后通常需要2次搜索來(lái)更新索引并寫入行。

前面的討論并不意味著你的應(yīng)用性能會(huì)因?yàn)閘og N而緩慢下降秀菱。只要內(nèi)容被OS或MySQL服務(wù)器緩存振诬,隨著表的變大,只會(huì)稍微變慢答朋。在數(shù)據(jù)量變得太大而無(wú)法緩存后贷揽,將會(huì)變慢很多,直到你的應(yīng)用程序受到磁盤搜索約束(按照l(shuí)og N增長(zhǎng))梦碗。為了避免這種情況禽绪,可以根據(jù)數(shù)據(jù)的增長(zhǎng)而增加key的。對(duì)于MyISAM表洪规,key的緩存大小由名為key_buffer_size的系統(tǒng)變量控制印屁,詳見 Section 5.1.1, “Configuring the Server”

參考文檔

點(diǎn)擊查看更多內(nèi)容

作者:大目
鏈接:https://www.imooc.com/article/308225
來(lái)源:慕課網(wǎng)
本文原創(chuàng)發(fā)布于慕課網(wǎng) 雄人,轉(zhuǎn)載請(qǐng)注明出處,謝謝合作

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末念赶,一起剝皮案震驚了整個(gè)濱河市础钠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件厂画,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡很钓,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門董栽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)码倦,“玉大人,你說(shuō)我怎么就攤上這事锭碳≡” “怎么了?”我有些...
    開封第一講書人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵擒抛,是天一觀的道長(zhǎng)运提。 經(jīng)常有香客問(wèn)我蝗柔,道長(zhǎng)闻葵,這世上最難降的妖魔是什么民泵? 我笑而不...
    開封第一講書人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮槽畔,結(jié)果婚禮上栈妆,老公的妹妹穿的比我還像新娘。我一直安慰自己厢钧,他們只是感情好鳞尔,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著早直,像睡著了一般寥假。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上霞扬,一...
    開封第一講書人閱讀 51,718評(píng)論 1 305
  • 那天糕韧,我揣著相機(jī)與錄音,去河邊找鬼喻圃。 笑死萤彩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的斧拍。 我是一名探鬼主播雀扶,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼肆汹!你這毒婦竟也來(lái)了愚墓?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤昂勉,失蹤者是張志新(化名)和其女友劉穎浪册,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體硼啤,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡议经,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了谴返。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片煞肾。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖嗓袱,靈堂內(nèi)的尸體忽然破棺而出籍救,到底是詐尸還是另有隱情,我是刑警寧澤渠抹,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布蝙昙,位于F島的核電站闪萄,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏奇颠。R本人自食惡果不足惜败去,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望烈拒。 院中可真熱鬧圆裕,春花似錦、人聲如沸荆几。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)吨铸。三九已至行拢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間诞吱,已是汗流浹背舟奠。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留狐胎,地道東北人鸭栖。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像握巢,于是被迫代替她去往敵國(guó)和親晕鹊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

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