MySQL優(yōu)化系列8-MySQL的執(zhí)行計(jì)劃介紹

備注:測(cè)試數(shù)據(jù)庫(kù)版本為MySQL 8.0

一.使用EXPLAIN優(yōu)化查詢

1.1 Explain語(yǔ)法及概述

語(yǔ)法:

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

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

{EXPLAIN | DESCRIBE | DESC} ANALYZE [FORMAT = TREE] 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
}

DESCRIBE和EXPLAIN語(yǔ)句是同義詞。在實(shí)踐中嫁艇,DESCRIBE關(guān)鍵字通常用于獲取關(guān)于表結(jié)構(gòu)的信息默刚,而EXPLAIN用于獲取查詢執(zhí)行計(jì)劃(即解釋MySQL如何執(zhí)行查詢)。

下面的討論將根據(jù)這些用法使用DESCRIBE和EXPLAIN關(guān)鍵字,但是MySQL解析器將它們視為完全同義的蹄殃。

1.1.1 獲取表結(jié)構(gòu)信息

DESCRIBE提供關(guān)于表中列的信息:

mysql> DESCRIBE City;
+------------+----------+------+-----+---------+----------------+
| Field      | Type     | Null | Key | Default | Extra          |
+------------+----------+------+-----+---------+----------------+
| Id         | int(11)  | NO   | PRI | NULL    | auto_increment |
| Name       | char(35) | NO   |     |         |                |
| Country    | char(3)  | NO   | UNI |         |                |
| District   | char(20) | YES  | MUL |         |                |
| Population | int(11)  | NO   |     | 0       |                |
+------------+----------+------+-----+---------+----------------+

描述是顯示列的快捷方式。這些語(yǔ)句還顯示視圖的信息你踩。SHOW COLUMNS的描述提供了有關(guān)輸出列的更多信息诅岩。

默認(rèn)情況下,DESCRIBE顯示表中所有列的信息带膜。如果給出Col_name吩谦,則是表中列的名稱。在這種情況下膝藕,語(yǔ)句只顯示指定列的信息式廷。野,如果給定芭挽,是一個(gè)模式字符串滑废。它可以包含SQL %和_通配符。在這種情況下袜爪,該語(yǔ)句只顯示名稱與字符串匹配的列的輸出蠕趁。字符串不需要用引號(hào)括起來(lái),除非它包含空格或其他特殊字符辛馆。

提供DESCRIBE語(yǔ)句是為了與Oracle兼容俺陋。

SHOW CREATE TABLE、SHOW TABLE STATUS和SHOW INDEX語(yǔ)句也提供了關(guān)于表的信息昙篙。

1.1.2 獲取執(zhí)行計(jì)劃信息

EXPLAIN語(yǔ)句提供了MySQL如何執(zhí)行語(yǔ)句的信息:

  1. EXPLAIN適用于SELECT倔韭、DELETE、INSERT瓢对、REPLACE和UPDATE語(yǔ)句寿酌。在MySQL 8.0.19及以后版本中,它也可以處理TABLE語(yǔ)句硕蛹。
  2. 當(dāng)EXPLAIN與可解釋性語(yǔ)句一起使用時(shí)醇疼,MySQL將顯示來(lái)自優(yōu)化器的關(guān)于語(yǔ)句執(zhí)行計(jì)劃的信息。也就是說(shuō)法焰,MySQL解釋了它將如何處理這條語(yǔ)句秧荆,包括關(guān)于表如何連接以及以何種順序連接的信息。
  3. 當(dāng)EXPLAIN與FOR CONNECTION connection_id一起使用時(shí)埃仪,而不是一個(gè)可解釋的語(yǔ)句乙濒,它將顯示在命名連接中執(zhí)行的語(yǔ)句的執(zhí)行計(jì)劃。
  4. 對(duì)于可解釋性語(yǔ)句,EXPLAIN生成可以使用SHOW WARNINGS顯示的附加執(zhí)行計(jì)劃信息颁股。
  5. EXPLAIN對(duì)于檢查涉及分區(qū)表的查詢非常有用么库。
  6. FORMAT選項(xiàng)可用于選擇輸出格式。TRADITIONAL以表格格式顯示輸出甘有。如果沒(méi)有FORMAT選項(xiàng)诉儒,這是默認(rèn)值。JSON格式以JSON格式顯示信息亏掀。在MySQL 8.0.16及以后版本中忱反,TREE提供了類似樹(shù)的輸出,比傳統(tǒng)格式提供了更精確的查詢處理描述;它是唯一顯示散列連接使用的格式滤愕,并且總是用于EXPLAIN ANALYZE温算。

EXPLAIN需要執(zhí)行被解釋語(yǔ)句所需的相同特權(quán)。此外间影,EXPLAIN還要求對(duì)任何已解釋的視圖具有SHOW VIEW特權(quán)米者。解釋……如果指定的連接屬于不同的用戶,那么FOR CONNECTION也需要PROCESS特權(quán)宇智。

在EXPLAIN的幫助下蔓搞,您可以看到應(yīng)該在表的哪些地方添加索引,以便通過(guò)使用索引查找行來(lái)加快語(yǔ)句的執(zhí)行速度随橘。您還可以使用EXPLAIN來(lái)檢查優(yōu)化器是否以最佳順序連接表喂分。要提示優(yōu)化器使用與SELECT語(yǔ)句中表的命名順序?qū)?yīng)的連接順序,請(qǐng)使用SELECT直線連接(而不是SELECT)開(kāi)始該語(yǔ)句机蔗。

優(yōu)化器跟蹤有時(shí)可能提供與EXPLAIN補(bǔ)充的信息蒲祈。但是,優(yōu)化器跟蹤格式和內(nèi)容可能會(huì)在不同版本之間發(fā)生變化萝嘁。詳細(xì)信息梆掸,請(qǐng)參見(jiàn)MySQL內(nèi)部:跟蹤優(yōu)化器。

如果您認(rèn)為索引應(yīng)該被使用牙言,但卻沒(méi)有使用酸钦,那么運(yùn)行ANALYZE TABLE來(lái)更新表的統(tǒng)計(jì)信息,例如鍵的基數(shù)咱枉,這些信息可能會(huì)影響優(yōu)化器做出的選擇卑硫。

1.1.3 使用EXPLAIN ANALYZE獲取信息

MySQL 8.0.18引入了EXPLAIN ANALYZE,它運(yùn)行一條語(yǔ)句并產(chǎn)生EXPLAIN輸出蚕断,以及計(jì)時(shí)和額外的欢伏、基于迭代器的信息,這些信息是關(guān)于優(yōu)化器的期望如何與實(shí)際執(zhí)行相匹配的亿乳。對(duì)于每個(gè)迭代器硝拧,提供以下信息:

  1. 估計(jì)執(zhí)行成本
    (有些迭代器沒(méi)有計(jì)入成本模型,因此不包括在估算中。)
  2. 估計(jì)返回的行數(shù)
  3. 該返回第一行了
  4. 返回所有行的時(shí)間(實(shí)際成本)障陶,以毫秒為單位
    (當(dāng)有多個(gè)循環(huán)時(shí)滋恬,該圖顯示了每個(gè)循環(huán)的平均時(shí)間。)
  5. 迭代器返回的行數(shù)
  6. 數(shù)量的循環(huán)

查詢執(zhí)行信息使用TREE輸出格式顯示咸这,其中節(jié)點(diǎn)表示迭代器夷恍。EXPLAIN ANALYZE總是使用TREE輸出格式魔眨。在MySQL 8.0.21及以后版本中媳维,可以使用FORMAT=TREE顯式指定。TREE以外的其他格式仍然不受支持遏暴。

EXPLAIN ANALYZE可以與SELECT語(yǔ)句一起使用侄刽,也可以與多表UPDATE和DELETE語(yǔ)句一起使用。從MySQL 8.0.19開(kāi)始朋凉,它也可以與TABLE語(yǔ)句一起使用州丹。

從MySQL 8.0.20開(kāi)始,您可以使用KILL QUERY或CTRL-C終止此語(yǔ)句杂彭。

解釋分析不能與FOR連接一起使用墓毒。

mysql> EXPLAIN ANALYZE SELECT * FROM t1 JOIN t2 ON (t1.c1 = t2.c2)\G
*************************** 1. row ***************************
EXPLAIN: -> Inner hash join (t2.c2 = t1.c1)  (cost=4.70 rows=6)
(actual time=0.032..0.035 rows=6 loops=1)
    -> Table scan on t2  (cost=0.06 rows=6)
(actual time=0.003..0.005 rows=6 loops=1)
    -> Hash
        -> Table scan on t1  (cost=0.85 rows=6)
(actual time=0.018..0.022 rows=6 loops=1)

mysql> EXPLAIN ANALYZE SELECT * FROM t3 WHERE i > 8\G
*************************** 1. row ***************************
EXPLAIN: -> Filter: (t3.i > 8)  (cost=1.75 rows=5)
(actual time=0.019..0.021 rows=6 loops=1)
    -> Table scan on t3  (cost=1.75 rows=15)
(actual time=0.017..0.019 rows=15 loops=1)

mysql> EXPLAIN ANALYZE SELECT * FROM t3 WHERE pk > 17\G
*************************** 1. row ***************************
EXPLAIN: -> Filter: (t3.pk > 17)  (cost=1.26 rows=5)
(actual time=0.013..0.016 rows=5 loops=1)
    -> Index range scan on t3 using PRIMARY  (cost=1.26 rows=5)
(actual time=0.012..0.014 rows=5 loops=1)

示例輸出中使用的表是由下面所示的語(yǔ)句創(chuàng)建的:

CREATE TABLE t1 (
    c1 INTEGER DEFAULT NULL,
    c2 INTEGER DEFAULT NULL
);

CREATE TABLE t2 (
    c1 INTEGER DEFAULT NULL,
    c2 INTEGER DEFAULT NULL
);

CREATE TABLE t3 (
    pk INTEGER NOT NULL PRIMARY KEY,
    i INTEGER DEFAULT NULL
);

二.Explain輸出格式

EXPLAIN語(yǔ)句提供了關(guān)于MySQL如何執(zhí)行語(yǔ)句的信息。EXPLAIN適用于SELECT亲怠、DELETE所计、INSERT团秽、REPLACE和UPDATE語(yǔ)句主胧。

EXPLAIN為SELECT語(yǔ)句中使用的每個(gè)表返回一行信息图毕。它按照MySQL在處理語(yǔ)句時(shí)讀取這些表的順序列出了輸出中的表治拿。這意味著MySQL從第一個(gè)表中讀取一行荞驴,然后在第二個(gè)表中找到匹配的行能犯,然后在第三個(gè)表中找到匹配的行,以此類推排苍。當(dāng)處理所有表時(shí)遗增,MySQL輸出所選列并回溯表列表康震,直到找到一個(gè)有更多匹配行的表。從這個(gè)表中讀取下一行卸奉,然后繼續(xù)讀取下一個(gè)表疹鳄。

2.1 EXPLAIN 輸出列

EXPLAIN的每個(gè)輸出行提供關(guān)于一個(gè)表的信息。每一行包含表中總結(jié)的值,并在表后面有更詳細(xì)的描述。列名顯示在表的第一列中;第二列提供了當(dāng)使用FORMAT=JSON時(shí)在輸出中顯示的等價(jià)屬性名。

EXPLAIN 輸出列信息:

列名 json名 含義
id select_id select語(yǔ)句的標(biāo)示符
select_type None select的類別
table table_name 輸出行的表
partitions partitions 匹配的分區(qū)
type access_type 表連接的類型
possible_keys possible_keys 可選擇的索引
key key 實(shí)際選擇的索引
key_len key_length 所選鍵的長(zhǎng)度
ref ref 與索引比較的列
rows rows 要檢查的行數(shù)的估計(jì)
filtered filtered 按表?xiàng)l件過(guò)濾的行百分比
Extra None 額外的信息

2.1.1 id (JSON name: select_id)

SELECT標(biāo)識(shí)符幻锁。這是查詢中SELECT的順序編號(hào)置谦。如果該行引用其他行的聯(lián)合結(jié)果葵擎,則該值可以為NULL谅阿。在本例中,表列顯示了一個(gè)類似于的值酬滤,表示該行指的是id值為M和N的行的并集签餐。

2.1.2 select_type (JSON name: none)

SELECT的類型,可以是下表中顯示的任何類型盯串。json格式的EXPLAIN將SELECT類型作為query_block的屬性公開(kāi)氯檐,除非它是SIMPLE或PRIMARY。表格中還顯示了JSON名稱(如果適用的話)体捏。

select_type值 json名 含義
SIMPLE None 簡(jiǎn)單的SELECT(不使用UNION或子查詢)
PRIMARY None 外層的選擇
UNION None UNION中的第二個(gè)或之后的SELECT語(yǔ)句
DEPENDENT UNION dependent (true) UNION中的第二個(gè)或之后的SELECT語(yǔ)句冠摄,依賴于外部查詢
UNION RESULT union_result UNION的結(jié)果
SUBQUERY None 子查詢中的第一個(gè)SELECT
DEPENDENT SUBQUERY dependent (true) 子查詢中的第一個(gè)SELECT ,依賴于外部查詢
DERIVED None 派生表
DEPENDENT DERIVED dependent (true) 依賴于另一個(gè)表的派生表
MATERIALIZED materialized_from_subquery 物化子查詢
UNCACHEABLE SUBQUERY cacheable (false) 不能緩存其結(jié)果的子查詢几缭,必須為外部查詢的每一行重新求值
UNCACHEABLE UNION cacheable (false) UNION中屬于非緩存子查詢的第二個(gè)或之后的選擇(參見(jiàn)非緩存子查詢)

dependency通常表示使用相關(guān)子查詢河泳。

從屬子查詢的計(jì)算不同于非緩存子查詢的計(jì)算。對(duì)于從屬子查詢年栓,子查詢只會(huì)對(duì)來(lái)自其外部上下文的變量的每一組不同值重新計(jì)算一次拆挥。對(duì)于UNCACHEABLE SUBQUERY,子查詢將針對(duì)外部上下文的每一行重新計(jì)算某抓。

當(dāng)你用EXPLAIN指定FORMAT=JSON時(shí)纸兔,輸出沒(méi)有直接等價(jià)于select_type的單個(gè)屬性;query_block屬性對(duì)應(yīng)于給定的SELECT。與剛才顯示的大多數(shù)SELECT子查詢類型等價(jià)的屬性是可用的(例如materialized_from_subquery用于MATERIALIZED)否副,并在適當(dāng)?shù)臅r(shí)候顯示汉矿。對(duì)于SIMPLE或PRIMARY,沒(méi)有對(duì)應(yīng)的JSON副编。

非select語(yǔ)句的select_type值顯示受影響表的語(yǔ)句類型负甸。例如,對(duì)于DELETE語(yǔ)句痹届,select_type是DELETE呻待。

2.1.3 table (JSON name: table_name)

輸出行所指的表的名稱。這也可以是以下值之一:

  1. 表示id值為M和N的行并集队腐。
  2. 這一行指的是id值為n的那一行的派生表結(jié)果蚕捉。例如,派生表可能來(lái)自from子句中的一個(gè)子查詢柴淘。
  3. 這一行是id值為n的實(shí)化子查詢的結(jié)果迫淹。

2.1.4 partitions (JSON name: partitions)

查詢將從其中匹配記錄的分區(qū)秘通。對(duì)于非分區(qū)表,該值為NULL.

2.1.5 type (JSON name: access_type)

EXPLAIN輸出的類型列描述了如何連接表敛熬。在json格式的輸出中肺稀,這些值是access_type屬性的值。下面的列表描述了連接類型应民,按照從最佳類型到最差類型的順序排列:
1.system
表只有一行(=系統(tǒng)表)话原。這是const連接類型的特殊情況。

  1. const
    表最多有一個(gè)匹配行诲锹,在查詢開(kāi)始時(shí)讀取繁仁。因?yàn)橹挥幸恍校栽撔兄辛兄械闹悼梢员粌?yōu)化器的其余部分視為常量归园。Const表非郴剖快,因?yàn)樗鼈冎槐蛔x取一次庸诱。
    const用于將主鍵或惟一索引的所有部分與常量值進(jìn)行比較捻浦。在以下查詢中,tbl_name可以作為const表使用:
SELECT * FROM tbl_name WHERE primary_key=1;

SELECT * FROM tbl_name
  WHERE primary_key_part1=1 AND primary_key_part2=2;
  1. eq_ref
    對(duì)于前一個(gè)表中的每一個(gè)行組合偶翅,都從這個(gè)表中讀取一行默勾。除了系統(tǒng)類型和const類型碉渡,這是最好的連接類型聚谁。當(dāng)連接使用索引的所有部分,且索引是主鍵或UNIQUE NOT NULL索引時(shí)滞诺,使用該索引形导。
    Eq_ref可用于使用=操作符進(jìn)行比較的索引列。比較值可以是一個(gè)常量或一個(gè)表達(dá)式习霹,該表達(dá)式使用在該表之前讀取的表中的列朵耕。在下面的例子中,MySQL可以使用eq_ref連接來(lái)處理ref_table:
SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column=other_table.column;

SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column_part1=other_table.column
  AND ref_table.key_column_part2=1;
  1. ref
    對(duì)于前一個(gè)表中的每個(gè)行組合淋叶,將從這個(gè)表中讀取索引值匹配的所有行阎曹。如果連接只使用鍵的最左邊的前綴,或者鍵不是主鍵或惟一索引(換句話說(shuō)煞檩,如果連接不能基于鍵值選擇單行)处嫌,則使用ref。如果使用的鍵只匹配幾行斟湃,這是一個(gè)很好的連接類型熏迹。

Ref可用于使用=或<=>操作符進(jìn)行比較的索引列。在下面的例子中凝赛,MySQL可以使用ref連接來(lái)處理ref_table:

SELECT * FROM ref_table WHERE key_column=expr;

SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column=other_table.column;

SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column_part1=other_table.column
  AND ref_table.key_column_part2=1;
  1. fulltext
    連接是使用FULLTEXT索引執(zhí)行的

  2. ref_or_null
    這種連接類型類似ref注暗,但是MySQL會(huì)對(duì)包含NULL值的行進(jìn)行額外的搜索坛缕。這種連接類型優(yōu)化最常用于解析子查詢。在下面的例子中捆昏,MySQL可以使用ref_or_null連接來(lái)處理ref_table:

SELECT * FROM ref_table
  WHERE key_column=expr OR key_column IS NULL;
  1. index_merge
    此連接類型表示使用了索引合并優(yōu)化赚楚。在本例中,輸出行中的鍵列包含所用索引的列表骗卜,而key_len包含所用索引的最長(zhǎng)鍵部分的列表.

  2. unique_subquery
    以下形式的IN子查詢用此類型替換eq_ref:

value IN (SELECT primary_key FROM single_table WHERE some_expr)

Unique_subquery只是一個(gè)索引查詢函數(shù)直晨,它完全取代了子查詢以提高效率

  1. index_subquery
    這種連接類型類似于unique_subquery。它取代了IN子查詢膨俐,但它適用于以下形式的子查詢中的非唯一索引:
value IN (SELECT key_column FROM single_table WHERE some_expr)
  1. range
    只檢索給定范圍內(nèi)的行勇皇,使用索引選擇行。輸出行中的鍵列表明使用了哪個(gè)索引焚刺。key_len包含所使用的最長(zhǎng)密鑰部分敛摘。對(duì)于這種類型,ref列是NULL乳愉。

range可以在鍵列與常量進(jìn)行比較時(shí)使用=兄淫,<>,>蔓姚,>=捕虽,<,<=坡脐,is NULL泄私, <=>, BETWEEN, LIKE, or IN()操作符:

SELECT * FROM tbl_name
  WHERE key_column = 10;

SELECT * FROM tbl_name
  WHERE key_column BETWEEN 10 and 20;

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

SELECT * FROM tbl_name
  WHERE key_part1 = 10 AND key_part2 IN (10,20,30);
  1. index
    索引連接類型與ALL相同备闲,只是要掃描索引樹(shù)晌端。這有兩種方式:
    11.1 如果索引是查詢的覆蓋索引,并且可以用于滿足表中所需的所有數(shù)據(jù)恬砂,則只掃描索引樹(shù)咧纠。在本例中,Extra列表示Using index泻骤。僅索引掃描通常比ALL更快漆羔,因?yàn)樗饕拇笮⊥ǔP∮诒頂?shù)據(jù)。
    11.2 使用從索引中讀取以按索引順序查找數(shù)據(jù)行來(lái)執(zhí)行全表掃描狱掂。Uses index不會(huì)出現(xiàn)在Extra列中演痒。
    當(dāng)查詢只使用屬于單個(gè)索引的列時(shí),MySQL可以使用這種連接類型符欠。

  2. ALL
    對(duì)前一個(gè)表中的每一個(gè)行組合執(zhí)行一次全表掃描嫡霞。如果表是第一個(gè)未被標(biāo)記為const的表,這通常是不好的希柿,在所有其他情況下通常是非常糟糕的诊沪。通常养筒,可以通過(guò)添加索引來(lái)避免使用ALL,這些索引支持基于常值從表中進(jìn)行行檢索端姚,或基于以前表中的列值進(jìn)行行檢索晕粪。

2.1.6 possible_keys (JSON name: possible_keys)

possible_keys列表示MySQL可以選擇從其中查找該表中的行的索引。注意渐裸,此列完全獨(dú)立于EXPLAIN輸出中顯示的表的順序巫湘。這意味著可能_keys中的一些鍵在實(shí)際生成的表順序中可能不可用。

如果該列為NULL(或在json格式的輸出中未定義)昏鹃,則沒(méi)有相關(guān)的索引尚氛。在這種情況下,您可以通過(guò)檢查WHERE子句來(lái)檢查它是否引用了一些或一些適合索引的列洞渤,從而提高查詢的性能阅嘶。如果是,創(chuàng)建一個(gè)適當(dāng)?shù)乃饕⒃俅问褂肊XPLAIN檢查查詢载迄。

要查看表有哪些索引讯柔,請(qǐng)使用SHOW INDEX FROM tbl_name。

2.1.7 key (JSON name: key)

鍵列表示MySQL實(shí)際決定使用的鍵(索引)护昧。如果MySQL決定使用一個(gè)可能的_keys索引來(lái)查找行魂迄,該索引將作為鍵值列出。

key可能會(huì)命名一個(gè)不存在于possible_keys值中的索引惋耙。如果沒(méi)有一個(gè)possible_keys索引適合查找行捣炬,但是查詢選擇的所有列都是其他一些索引的列,就會(huì)發(fā)生這種情況怠晴。也就是說(shuō)遥金,已命名的索引涵蓋所選的列,因此盡管它不用于確定要檢索哪些行蒜田,但索引掃描比數(shù)據(jù)行掃描更有效。

對(duì)于InnoDB來(lái)說(shuō)选泻,即使查詢也選擇了主鍵冲粤,輔助索引也可能涵蓋所選列,因?yàn)镮nnoDB會(huì)在每個(gè)輔助索引中存儲(chǔ)主鍵值页眯。如果key是NULL, MySQL找不到索引來(lái)更有效地執(zhí)行查詢梯捕。

要強(qiáng)制MySQL使用或忽略列中列出的索引,請(qǐng)?jiān)诓樵冎惺褂胒orce index窝撵、use index或ignore index傀顾。

對(duì)于MyISAM表,運(yùn)行ANALYZE TABLE可以幫助優(yōu)化器選擇更好的索引碌奉。對(duì)于MyISAM表短曾,myisamchk -analyze也做同樣的工作寒砖。

2.1.8 key_len (JSON name: key_length)

key_len列表示MySQL決定使用的密鑰的長(zhǎng)度。key_len的值使您能夠確定MySQL實(shí)際使用多部分密鑰的多少部分嫉拐。如果鍵列說(shuō)NULL, key_len列也說(shuō)NULL哩都。

由于鍵存儲(chǔ)格式的原因,可以為NULL的列的鍵長(zhǎng)度比NOT NULL的列大一個(gè)婉徘。

2.1.9 ref (JSON name: ref)

ref列顯示哪些列或常量與鍵列中指定的索引進(jìn)行比較漠嵌,以從表中選擇行。

如果值是func,則使用的值是某個(gè)函數(shù)的結(jié)果墩划。要查看哪個(gè)函數(shù)唬涧,請(qǐng)?jiān)贓XPLAIN后面使用SHOW WARNINGS來(lái)查看擴(kuò)展的EXPLAIN輸出。函數(shù)實(shí)際上可能是一個(gè)運(yùn)算符挺身,比如算術(shù)運(yùn)算符。

2.1.10 rows (JSON name: rows)

rows列表示MySQL認(rèn)為在執(zhí)行查詢時(shí)必須檢查的行數(shù)锌仅。

對(duì)于InnoDB表章钾,這個(gè)數(shù)字是一個(gè)估計(jì)值,可能并不總是準(zhǔn)確的热芹。

2.1.11 filtered (JSON name: filtered)

篩選列指示由表?xiàng)l件篩選的表行的估計(jì)百分比贱傀。最大值是100,這意味著沒(méi)有對(duì)行進(jìn)行過(guò)濾伊脓。從100開(kāi)始減小的值表示過(guò)濾的數(shù)量在增加府寒。Rows顯示所檢查的估計(jì)行數(shù),而行×過(guò)濾顯示與下表連接的行數(shù)报腔。例如株搔,如果rows為1000,而filtered為50.00(50%)纯蛾,則連接到下表的行數(shù)為1000 × 50% = 500纤房。

2.1.12 Extra (JSON name: none)

沒(méi)有一個(gè)JSON屬性對(duì)應(yīng)Extra列;但是,可以出現(xiàn)在此列中的值將作為JSON屬性或消息屬性的文本公開(kāi)翻诉。

EXPLAIN輸出的Extra列包含關(guān)于MySQL如何解析查詢的額外信息炮姨。下面的列表解釋了此列中可能出現(xiàn)的值。每個(gè)項(xiàng)還指示json格式的輸出碰煌,哪個(gè)屬性顯示Extra值舒岸。對(duì)于其中一些,有一個(gè)特定的屬性芦圾。其他的顯示為message屬性的文本蛾派。

如果您希望盡可能快地進(jìn)行查詢,請(qǐng)注意Using filesort和Using temporary的Extra列值,或者在json格式的EXPLAIN輸出中洪乍,對(duì)于using_filesort和using_temporary_table屬性等于true眯杏。

  1. Backward index scan (JSON: backward_index_scan)
    優(yōu)化器可以在InnoDB表上使用降序索引。與Using index一起顯示典尾。

  2. Child of 'table' pushed join@1 (JSON: message text)
    這個(gè)表在一個(gè)可以下推到NDB內(nèi)核的連接中作為table的子表被引用役拴。僅適用于NDB集群,當(dāng)下推連接被啟用時(shí)钾埂。有關(guān)更多信息和示例河闰,請(qǐng)參見(jiàn)ndb_join_pushdown服務(wù)器系統(tǒng)變量的描述。

  3. const row not found (JSON property: const_row_not_found)
    對(duì)于諸如SELECT…from tbl_name褥紫,表是空的姜性。

  4. Deleting all rows (JSON property: message)
    對(duì)于DELETE,一些存儲(chǔ)引擎(如MyISAM)支持以一種簡(jiǎn)單而快速的方式刪除所有表行的處理程序方法髓考。如果引擎使用此優(yōu)化部念,則顯示此Extra值。

  5. Distinct (JSON property: distinct)
    MySQL正在尋找不同的值氨菇,所以當(dāng)它找到第一個(gè)匹配的行后儡炼,它就停止為當(dāng)前的行組合搜索更多的行。

  6. FirstMatch(tbl_name) (JSON property: first_match)
    對(duì)tbl_name使用semijoin FirstMatch連接捷徑策略查蓉。

  7. Full scan on NULL key (JSON property: message)
    當(dāng)優(yōu)化器不能使用索引查找訪問(wèn)方法時(shí)乌询,將子查詢優(yōu)化作為一種回退策略出現(xiàn)這種情況。

  8. Impossible HAVING (JSON property: message)
    HAVING子句總是false豌研,不能選擇任何行妹田。

  9. Impossible WHERE (JSON property: message)
    WHERE子句總是false,不能選擇任何行鹃共。

  10. Impossible WHERE noticed after reading const tables (JSON property: message)
    MySQL已經(jīng)讀取了所有的const(和system)表鬼佣,注意WHERE子句總是為false。

  11. LooseScan(m..n) (JSON property: message)
    采用半join LooseScan策略霜浴。M和n是關(guān)鍵零件號(hào)晶衷。

  12. No matching min/max row (JSON property: message)
    沒(méi)有一行滿足查詢的條件,例如SELECT MIN(…)從…條件的地方坷随。

  13. no matching row in const table (JSON property: message)
    對(duì)于帶有連接的查詢房铭,存在一個(gè)空表或沒(méi)有行滿足惟一索引條件的表。

  14. No matching rows after partition pruning (JSON property: message)
    對(duì)于DELETE或UPDATE温眉,在分區(qū)剪枝之后,優(yōu)化器沒(méi)有發(fā)現(xiàn)需要?jiǎng)h除或更新的內(nèi)容翁狐。它的意義類似于SELECT語(yǔ)句的Impossible WHERE类溢。

  15. No tables used (JSON property: message)
    查詢沒(méi)有FROM子句,或者有FROM DUAL子句。
    對(duì)于INSERT或REPLACE語(yǔ)句闯冷,EXPLAIN在沒(méi)有SELECT部分時(shí)顯示此值砂心。例如,它出現(xiàn)在EXPLAIN INSERT INTO t VALUES(10)中蛇耀,因?yàn)樗葍r(jià)于EXPLAIN INSERT INTO t SELECT 10 FROM DUAL辩诞。

  16. Not exists (JSON property: message)
    MySQL能夠?qū)Σ樵冞M(jìn)行LEFT JOIN優(yōu)化,并且在找到匹配LEFT JOIN條件的行后纺涤,不會(huì)檢查該表中先前的行組合的更多行译暂。下面是一個(gè)可以通過(guò)這種方式優(yōu)化的查詢類型的示例:

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拧咳,并且不會(huì)掃描t2中具有相同id值的其余行伯顶。換句話說(shuō),對(duì)于t1中的每一行骆膝,MySQL只需要在t2中進(jìn)行一次查找祭衩,而不管t2中有多少行匹配。
在MySQL 8.0.17及以后版本中阅签,這也可以表明一個(gè)形式為NOT In(子查詢)或NOT EXISTS(子查詢)的WHERE條件已經(jīng)被內(nèi)部轉(zhuǎn)換為反連接掐暮。這將刪除子查詢,并將其表帶入最頂層查詢的計(jì)劃中愉择,從而提供改進(jìn)的成本計(jì)劃劫乱。通過(guò)合并半連接和反連接,優(yōu)化器可以更自由地對(duì)執(zhí)行計(jì)劃中的表進(jìn)行重新排序锥涕,在某些情況下可以獲得更快的計(jì)劃衷戈。
通過(guò)檢查來(lái)自SHOW WARNINGS的Message列,或者在EXPLAIN FORMAT=TREE的輸出中层坠,可以看到何時(shí)為給定查詢執(zhí)行了反連接轉(zhuǎn)換殖妇。

  1. Plan isn't ready yet (JSON property: none)
    當(dāng)優(yōu)化器還沒(méi)有為已命名連接中執(zhí)行的語(yǔ)句創(chuàng)建執(zhí)行計(jì)劃時(shí),EXPLAIN FOR CONNECTION會(huì)出現(xiàn)此值破花。如果執(zhí)行計(jì)劃輸出包含多行谦趣,則其中任何一行或所有一行都可能有這個(gè)Extra值,這取決于優(yōu)化器在確定完整執(zhí)行計(jì)劃方面的進(jìn)度座每。

  2. Range checked for each record (index map: N) (JSON property: message)
    MySQL發(fā)現(xiàn)沒(méi)有好的索引可以使用前鹅,但是發(fā)現(xiàn)有些索引可能在已知前一個(gè)表的列值后使用。對(duì)于上表中的每個(gè)行組合峭梳,MySQL檢查是否可以使用range或index_merge訪問(wèn)方法來(lái)檢索行舰绘。這不是非常快,但比執(zhí)行沒(méi)有索引的連接要快捂寿。
    索引從1開(kāi)始編號(hào)口四,順序與表的SHOW INDEX相同。索引映射值N是位掩碼值秦陋,表示哪些索引是候選索引蔓彩。例如,值0x19(二進(jìn)制11001)表示考慮索引1驳概、4和5赤嚼。

  3. Recursive (JSON property: recursive)
    這表明該行適用于遞歸公共表表達(dá)式的遞歸SELECT部分。

  4. Rematerialize (JSON property: rematerialize)
    Rematerialize (X抡句,…)顯示在表T的EXPLAIN行中探膊,其中X是任何橫向派生表,它的Rematerialize在讀取新行T時(shí)被觸發(fā)待榔。例如:

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

每次top查詢處理新行t時(shí)逞壁,將重新物化派生表的內(nèi)容,使其更新锐锣。

  1. Scanned N databases (JSON property: message)
    這表示服務(wù)器在處理對(duì)INFORMATION_SCHEMA表的查詢時(shí)執(zhí)行多少個(gè)目錄掃描.

  2. Select tables optimized away (JSON property: message)
    優(yōu)化器確定1)應(yīng)該最多返回一行腌闯,2)為了產(chǎn)生這一行,必須讀取一組確定的行雕憔。當(dāng)可以在優(yōu)化階段讀取要讀取的行(例如姿骏,通過(guò)讀取索引行)時(shí),在查詢執(zhí)行期間不需要讀取任何表斤彼。
    當(dāng)查詢被隱式分組(包含一個(gè)聚合函數(shù)但沒(méi)有GROUP BY子句)時(shí)分瘦,第一個(gè)條件將被滿足。當(dāng)對(duì)使用的每個(gè)索引執(zhí)行一個(gè)行查詢時(shí)琉苇,就滿足了第二個(gè)條件嘲玫。讀取的索引數(shù)決定了要讀取的行數(shù)。
    考慮以下隱式分組查詢:

SELECT MIN(c1), MIN(c2) FROM t1;

假設(shè)MIN(c1)可以通過(guò)讀取一個(gè)索引行來(lái)檢索并扇,MIN(c2)可以通過(guò)從不同的索引讀取一行來(lái)檢索去团。也就是說(shuō),對(duì)于每個(gè)列c1和c2穷蛹,存在一個(gè)索引土陪,其中該列是該索引的第一列。在本例中肴熏,將返回一行鬼雀,這是通過(guò)讀取兩個(gè)確定性行產(chǎn)生的。
如果要讀取的行不是確定性的蛙吏,則不會(huì)出現(xiàn)此Extra值取刃√0梗考慮一下這個(gè)查詢:

SELECT MIN(c2) FROM t1 WHERE c1 <= 10;

假設(shè)(c1, c2)是一個(gè)覆蓋指標(biāo)出刷。使用這個(gè)索引璧疗,必須掃描所有c1 <= 10的行,以找到最小的c2值馁龟。相比之下崩侠,考慮以下查詢:

SELECT MIN(c2) FROM t1 WHERE c1 = 10;

在本例中,c1 = 10的第一個(gè)索引行包含最小的c2值坷檩。必須只讀取一行以產(chǎn)生返回的行却音。
對(duì)于每個(gè)表維護(hù)一個(gè)精確的行數(shù)的存儲(chǔ)引擎(如MyISAM,但不是InnoDB)矢炼,這個(gè)額外的值可以出現(xiàn)在count(*)查詢系瓢,其中WHERE子句缺失或總是true,沒(méi)有GROUP BY子句句灌。(這是隱式分組查詢的一個(gè)實(shí)例夷陋,在該查詢中存儲(chǔ)引擎會(huì)影響是否可以確定地讀取行數(shù)。)

  1. Skip_open_table, Open_frm_only, Open_full_table (JSON property: message)
    這些值表示應(yīng)用于查詢INFORMATION_SCHEMA表的文件打開(kāi)優(yōu)化胰锌。
  1. Skip_open_table:不需要打開(kāi)表文件骗绕。這些信息已經(jīng)可以從數(shù)據(jù)字典中獲得。
  2. Open_frm_only:表信息只需要讀取數(shù)據(jù)字典资昧。
  3. Open_full_table:未優(yōu)化的信息查詢酬土。表信息必須從數(shù)據(jù)字典中讀取,并通過(guò)讀取表文件格带。
  1. Start temporary, End temporary (JSON property: message)
    這表示使用半連接Duplicate weed策略的臨時(shí)表撤缴。

  2. unique row not found (JSON property: message)
    查詢,如SELECT…從tbl_name叽唱,沒(méi)有行滿足唯一索引或表上的主鍵的條件屈呕。

  3. Using filesort (JSON property: using_filesort)
    MySQL必須做一個(gè)額外的步驟來(lái)找出如何檢索排序的行。排序是根據(jù)連接類型遍歷所有行尔觉,并存儲(chǔ)與WHERE子句匹配的所有行的排序鍵和指向該行的指針凉袱。然后對(duì)鍵進(jìn)行排序,并按排序順序檢索行侦铜。

  4. Using index (JSON property: using_index)
    僅使用索引樹(shù)中的信息從表中檢索列信息专甩,而不必執(zhí)行額外的查找來(lái)讀取實(shí)際的行。當(dāng)查詢只使用屬于單個(gè)索引的列時(shí)钉稍,可以使用此策略涤躲。
    對(duì)于具有用戶定義的聚集索引的InnoDB表,即使Extra列中沒(méi)有Using index贡未,也可以使用該索引种樱。如果type是index, key是PRIMARY蒙袍,就會(huì)出現(xiàn)這種情況。
    EXPLAIN FORMAT=TRADITIONAL和EXPLAIN FORMAT=JSON中顯示了所有覆蓋索引的信息嫩挤。從MySQL 8.0.27開(kāi)始害幅,也顯示了EXPLAIN FORMAT=TREE。

  5. Using index condition (JSON property: using_index_condition)
    通過(guò)訪問(wèn)索引元組來(lái)讀取表岂昭,并首先測(cè)試它們以现,以確定是否讀取完整的表行。這樣约啊,除非必要邑遏,索引信息用于延遲(“下推”)讀取全表行。

  6. Using index for group-by (JSON property: using_index_for_group_by)
    與使用索引表訪問(wèn)方法類似恰矩,對(duì)于GROUP - BY使用索引表示MySQL找到了一個(gè)索引记盒,該索引可用于檢索GROUP BY或DISTINCT查詢的所有列,而無(wú)需對(duì)實(shí)際表進(jìn)行任何額外的磁盤訪問(wèn)外傅。此外纪吮,索引是以最有效的方式使用的,因此對(duì)于每個(gè)組栏豺,只讀取少數(shù)索引項(xiàng)彬碱。

  7. Using index for skip scan (JSON property: using_index_for_skip_scan)
    使用“跳過(guò)掃描”訪問(wèn)方式。

  8. Using join buffer (Block Nested Loop), Using join buffer (Batched Key Access), Using join buffer (hash join) (JSON property: using_join_buffer)
    早期連接中的表被部分讀入連接緩沖區(qū)奥洼,然后從緩沖區(qū)使用它們的行來(lái)執(zhí)行與當(dāng)前表的連接巷疼。(Block Nested Loop)表示使用塊嵌套循環(huán)算法,(Batched Key Access)表示使用批密鑰訪問(wèn)算法灵奖,(hash join)表示使用哈希連接嚼沿。也就是說(shuō),在EXPLAIN輸出的前面一行上的表中的鍵被緩沖瓷患,匹配的行被從使用join buffer中出現(xiàn)的行所表示的表中批量獲取骡尽。
    在json格式的輸出中,using_join_buffer的值總是塊嵌套循環(huán)擅编、批密鑰訪問(wèn)或散列連接中的一個(gè)攀细。
    哈希連接從MySQL 8.0.18開(kāi)始可用;Block Nested-Loop算法在MySQL 8.0.20或更高版本中沒(méi)有使用。

  9. Using MRR (JSON property: message)
    使用多范圍讀優(yōu)化策略讀取表爱态。

  10. Using sort_union(...), Using union(...), Using intersect(...) (JSON property: message)
    它們表明了特定的算法谭贪,顯示了索引掃描如何為index_merge連接類型合并。

  11. Using temporary (JSON property: using_temporary_table)
    為了解析查詢锦担,MySQL需要?jiǎng)?chuàng)建一個(gè)臨時(shí)表來(lái)保存結(jié)果俭识。如果查詢包含以不同方式列出列的GROUP BY和ORDER BY子句,通常會(huì)發(fā)生這種情況洞渔。

  12. Using where (JSON property: attached_condition)
    WHERE子句用于限制哪些行與下一個(gè)表匹配或發(fā)送給客戶端套媚。除非你特別想從表中獲取或檢查所有的行缚态,如果Extra值不是Using where,并且表連接類型是all或index堤瘤,那么你的查詢可能有問(wèn)題玫芦。
    在沒(méi)有直接對(duì)應(yīng)json格式輸出的地方使用;attachhed_condition屬性包含任何使用的WHERE條件。

  13. Using where with pushed condition (JSON property: message)
    僅適用于NDB表宙橱。這意味著NDB Cluster使用條件下推優(yōu)化來(lái)提高非索引列和常量之間直接比較的效率姨俩。在這種情況下,條件被“下推”到集群的數(shù)據(jù)節(jié)點(diǎn)师郑,并同時(shí)對(duì)所有數(shù)據(jù)節(jié)點(diǎn)進(jìn)行評(píng)估。這樣就不需要通過(guò)網(wǎng)絡(luò)發(fā)送不匹配的行调窍,并且可以將查詢速度提高5到10倍宝冕,而不需要使用Condition Pushdown。

  14. Zero limit (JSON property: message)
    查詢有一個(gè)LIMIT 0子句邓萨,不能選擇任何行地梨。

三. 獲取命名連接的執(zhí)行計(jì)劃信息

獲取在指定連接中執(zhí)行的可解釋語(yǔ)句的執(zhí)行計(jì)劃,使用此語(yǔ)句:

EXPLAIN [options] FOR CONNECTION connection_id;

EXPLAIN FOR CONNECTION返回當(dāng)前用于在給定連接中執(zhí)行查詢的EXPLAIN信息缔恳。由于對(duì)數(shù)據(jù)(和支持統(tǒng)計(jì)數(shù)據(jù))的更改宝剖,它可能產(chǎn)生與對(duì)等價(jià)查詢文本運(yùn)行EXPLAIN不同的結(jié)果。這種行為上的差異有助于診斷更多的瞬態(tài)性能問(wèn)題歉甚。例如万细,如果您在一個(gè)需要很長(zhǎng)時(shí)間才能完成的會(huì)話中運(yùn)行一條語(yǔ)句,那么在另一個(gè)會(huì)話中使用EXPLAIN For CONNECTION可能會(huì)產(chǎn)生有關(guān)延遲原因的有用信息纸泄。

connection_id是連接標(biāo)識(shí)符赖钞,可以從INFORMATION_SCHEMA PROCESSLIST表或SHOW PROCESSLIST語(yǔ)句中獲取。如果您擁有PROCESS特權(quán)聘裁,則可以為任何連接指定標(biāo)識(shí)符雪营。否則,您只能為自己的連接指定標(biāo)識(shí)符衡便。在所有情況下献起,您必須擁有足夠的權(quán)限來(lái)解釋指定連接上的查詢。

如果指定的連接沒(méi)有執(zhí)行語(yǔ)句镣陕,則結(jié)果為空谴餐。否則,只有在命名連接中執(zhí)行的語(yǔ)句是可解釋的時(shí)茁彭,EXPLAIN FOR CONNECTION才會(huì)應(yīng)用总寒。這包括選擇、刪除理肺、插入摄闸、替換和更新善镰。(但是,EXPLAIN FOR CONNECTION不適用于準(zhǔn)備語(yǔ)句年枕,即使是那些類型的準(zhǔn)備語(yǔ)句炫欺。)

如果指定的連接正在執(zhí)行一個(gè)可解釋語(yǔ)句,那么輸出就是您在語(yǔ)句本身上使用EXPLAIN所獲得的輸出熏兄。

操作步驟 session1 session2
獲取connect_id SELECT CONNECTION_ID();
也可以通過(guò)show processlist查看
查看其它連接正在執(zhí)行sql的執(zhí)行計(jì)劃 EXPLAIN FOR CONNECTION 8;
-- session1
mysql> SELECT CONNECTION_ID();
+-----------------+
| CONNECTION_ID() |
+-----------------+
|               8 |
+-----------------+
1 row in set (0.00 sec)

mysql> select count(*) from fact_sale_new;

-- session2
mysql> EXPLAIN FOR CONNECTION 8;
+----+-------------+---------------+------------+-------+---------------+---------+---------+------+-----------+----------+-------------+
| id | select_type | table         | partitions | type  | possible_keys | key     | key_len | ref  | rows      | filtered | Extra       |
+----+-------------+---------------+------------+-------+---------------+---------+---------+------+-----------+----------+-------------+
|  1 | SIMPLE      | fact_sale_new | NULL       | index | NULL          | PRIMARY | 8       | NULL | 766191222 |   100.00 | Using index |
+----+-------------+---------------+------------+-------+---------------+---------+---------+------+-----------+----------+-------------+
1 row in set (0.00 sec)

四. 評(píng)估查詢性能

在大多數(shù)情況下品洛,可以通過(guò)計(jì)算磁盤尋找數(shù)來(lái)估計(jì)查詢性能。對(duì)于小表摩桶,通城抛矗可以在一個(gè)磁盤查找中找到一行(因?yàn)樗饕赡鼙痪彺媪?。對(duì)于更大的表硝清,您可以估計(jì)辅斟,使用B-tree索引,您需要這么多文件來(lái)查找一行:log(row_count) / log(index_block_length / 3 * 2 / (index_length + data_pointer_length)) + 1芦拿。

在MySQL中士飒,一個(gè)索引塊通常是1024字節(jié),而數(shù)據(jù)指針通常是4字節(jié)蔗崎。對(duì)于500000行酵幕、鍵值長(zhǎng)度為3字節(jié)(MEDIUMINT的大小)的表,公式表示log(500,000)/log(1024/3*2/(3+4)) + 1 = 4次查找缓苛。

這個(gè)索引將需要大約500,000 * 7 * 3/2 = 5.2MB的存儲(chǔ)(假設(shè)典型的索引緩沖區(qū)填充率為2/3)芳撒,因此您可能在內(nèi)存中有很多索引,因此只需要一次或兩次調(diào)用來(lái)讀取數(shù)據(jù)來(lái)找到行他嫡。

但是番官,對(duì)于寫操作,您需要4個(gè)查找請(qǐng)求來(lái)找到放置新索引值的位置钢属,通常需要兩個(gè)查找請(qǐng)求來(lái)更新索引和寫入行徘熔。

前面的討論并不意味著你的應(yīng)用程序性能在日志n時(shí)就會(huì)慢慢下降。只要所有的東西都被操作系統(tǒng)或MySQL服務(wù)器緩存淆党,當(dāng)表變大時(shí)酷师,事情只會(huì)稍微變慢。當(dāng)數(shù)據(jù)變得太大而不能被緩存時(shí)染乌,事情就會(huì)變得非常慢山孔,直到你的應(yīng)用程序只被磁盤請(qǐng)求綁定(增加了log N)。為了避免這種情況荷憋,隨著數(shù)據(jù)的增長(zhǎng)增加關(guān)鍵緩存的大小台颠。對(duì)于MyISAM表,鍵緩存大小由key_buffer_size系統(tǒng)變量控制。

五.查看執(zhí)行計(jì)劃的實(shí)例

我們來(lái)運(yùn)行幾個(gè)簡(jiǎn)單的查詢串前,來(lái)看幾個(gè)執(zhí)行計(jì)劃的例子瘫里。

代碼:

select e.ename,d.dname from emp e,dept d where e.deptno = d.deptno;  

通過(guò)三種格式來(lái)查看上段sql代碼的執(zhí)行計(jì)劃:
常規(guī)格式

mysql> EXPLAIN  select e.ename,d.dname from emp e,dept d where e.deptno = d.deptno;  
+----+-------------+-------+------------+------+---------------+-----------+---------+---------------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key       | key_len | ref           | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+-----------+---------+---------------+------+----------+-------+
|  1 | SIMPLE      | d     | NULL       | ALL  | PRIMARY       | NULL      | NULL    | NULL          |    4 |   100.00 | NULL  |
|  1 | SIMPLE      | e     | NULL       | ref  | FK_DEPTNO     | FK_DEPTNO | 5       | test.d.deptno |    4 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+-----------+---------+---------------+------+----------+-------+
2 rows in set, 1 warning (0.01 sec)

json格式

mysql> EXPLAIN FORMAT=JSON select e.ename,d.dname from emp e,dept d where e.deptno = d.deptno\G
*************************** 1. row ***************************
EXPLAIN: {
  "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "4.52"
    },
    "nested_loop": [
      {
        "table": {
          "table_name": "d",
          "access_type": "ALL",
          "possible_keys": [
            "PRIMARY"
          ],
          "rows_examined_per_scan": 4,
          "rows_produced_per_join": 4,
          "filtered": "100.00",
          "cost_info": {
            "read_cost": "0.25",
            "eval_cost": "0.40",
            "prefix_cost": "0.65",
            "data_read_per_join": "384"
          },
          "used_columns": [
            "deptno",
            "dname"
          ]
        }
      },
      {
        "table": {
          "table_name": "e",
          "access_type": "ref",
          "possible_keys": [
            "FK_DEPTNO"
          ],
          "key": "FK_DEPTNO",
          "used_key_parts": [
            "deptno"
          ],
          "key_length": "5",
          "ref": [
            "test.d.deptno"
          ],
          "rows_examined_per_scan": 4,
          "rows_produced_per_join": 18,
          "filtered": "100.00",
          "cost_info": {
            "read_cost": "2.00",
            "eval_cost": "1.87",
            "prefix_cost": "4.52",
            "data_read_per_join": "1K"
          },
          "used_columns": [
            "ename",
            "deptno"
          ]
        }
      }
    ]
  }
}
1 row in set, 1 warning (0.00 sec)

mysql> 

tree格式


mysql> EXPLAIN FORMAT=TREE select e.ename,d.dname from emp e,dept d where e.deptno = d.deptno\G
*************************** 1. row ***************************
EXPLAIN: -> Nested loop inner join  (cost=4.52 rows=19)
    -> Table scan on d  (cost=0.65 rows=4)
    -> Index lookup on e using FK_DEPTNO (deptno=d.deptno)  (cost=0.62 rows=5)

1 row in set (0.00 sec)

參考:

  1. https://dev.mysql.com/doc/refman/8.0/en/execution-plan-information.html
  2. 《高性能MySQL》
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市荡碾,隨后出現(xiàn)的幾起案子谨读,更是在濱河造成了極大的恐慌,老刑警劉巖坛吁,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件劳殖,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡拨脉,警方通過(guò)查閱死者的電腦和手機(jī)哆姻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)女坑,“玉大人填具,你說(shuō)我怎么就攤上這事〈移” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵誉简,是天一觀的道長(zhǎng)碉就。 經(jīng)常有香客問(wèn)我,道長(zhǎng)闷串,這世上最難降的妖魔是什么瓮钥? 我笑而不...
    開(kāi)封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮烹吵,結(jié)果婚禮上碉熄,老公的妹妹穿的比我還像新娘。我一直安慰自己肋拔,他們只是感情好锈津,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著凉蜂,像睡著了一般琼梆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上窿吩,一...
    開(kāi)封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天茎杂,我揣著相機(jī)與錄音,去河邊找鬼纫雁。 笑死煌往,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的轧邪。 我是一名探鬼主播刽脖,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼羞海,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了曾棕?” 一聲冷哼從身側(cè)響起扣猫,我...
    開(kāi)封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎翘地,沒(méi)想到半個(gè)月后申尤,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡衙耕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年昧穿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片橙喘。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡时鸵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出厅瞎,到底是詐尸還是另有隱情饰潜,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布和簸,位于F島的核電站彭雾,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏锁保。R本人自食惡果不足惜薯酝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望爽柒。 院中可真熱鬧吴菠,春花似錦、人聲如沸浩村。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)穴亏。三九已至蜂挪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間嗓化,已是汗流浹背棠涮。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留刺覆,地道東北人严肪。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親驳糯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子篇梭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

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