?EXPLAIN?SELECT?1;其實(shí)除了以SELECT開頭的查詢語句,其余的DELETE、INSERT、REPLACE以及UPDATE語句前邊都可以加上EXPLAIN這個(gè)詞兒,用來查看這些語句的執(zhí)行計(jì)劃建兩張測(cè)試表:CREATE?T..." />
<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          最完整的Explain總結(jié),SQL優(yōu)化不再困難

          共 12063字,需瀏覽 25分鐘

           ·

          2020-10-25 04:38

          先看看具體有哪些字段:

          mysql>?EXPLAIN?SELECT?1;

          其實(shí)除了以SELECT開頭的查詢語句,其余的DELETE、INSERT、REPLACE以及UPDATE語句前邊都可以加上EXPLAIN這個(gè)詞兒,用來查看這些語句的執(zhí)行計(jì)劃

          建兩張測(cè)試表:

          CREATE?TABLE?t1?(
          ????id?INT?NOT?NULL?AUTO_INCREMENT,
          ????key1?VARCHAR(100),
          ????key2?VARCHAR(100),
          ????key3?VARCHAR(100),
          ????name?VARCHAR(100),
          ????PRIMARY?KEY?(id),
          ????KEY?idx_key1?(key1),
          ????KEY?idx_key2_key3(key2,?key3)
          )?Engine=InnoDB?CHARSET=utf8;

          CREATE?TABLE?t2?(
          ????id?INT?NOT?NULL?AUTO_INCREMENT,
          ????key1?VARCHAR(100),
          ????key2?VARCHAR(100),
          ????key3?VARCHAR(100),
          ????name?VARCHAR(100),
          ????PRIMARY?KEY?(id),
          ????KEY?idx_key1?(key1),
          ????KEY?idx_key2_key3(key2,?key3)
          )?Engine=InnoDB?CHARSET=utf8;

          兩個(gè)變種

          explain extended

          會(huì)在 explain 的基礎(chǔ)上額外提供一些查詢優(yōu)化的信息。緊隨其后通過 show warnings 命令可以 得到優(yōu)化后的查詢語句,從而看出優(yōu)化器優(yōu)化了什么

          explain?extended?SELECT?*?FROM?t1?where?key1?=?'11';
          show?warnings;

          explain partitions

          相比 explain 多了個(gè) partitions 字段,如果查詢是基于分區(qū)表的話,會(huì)顯示查詢將訪問的分區(qū)。

          EXPLAIN?PARTITIONS?SELECT?*?FROM?t1?INNER?JOIN?t2?ON?t1.key3?=?t2.key3;

          table列

          這一列表示 explain 的一行正在訪問哪個(gè)表

          mysql>?EXPLAIN?SELECT?*?FROM?t1;

          這個(gè)查詢語句只涉及對(duì)t1表的單表查詢,所以EXPLAIN輸出中只有一條記錄,其中的table列的值是t1,表明這條記錄是用來說明對(duì)t1表的單表訪問。

          mysql>?EXPLAIN?SELECT?*?FROM?t1?INNER?JOIN?t2;

          可以看到這個(gè)連接查詢的執(zhí)行計(jì)劃中有兩條記錄,這兩條記錄的table列分別是t1和t2,這兩條記錄用來分別說明對(duì)t1表和t2表的訪問

          注意:

          當(dāng) from 子句中有子查詢時(shí),table列是??格式,表示當(dāng)前查詢依賴 id=N 的查詢,于是先執(zhí)行 id=N 的查詢。當(dāng)有 union 時(shí),UNION RESULT 的 table 列的值為,1和2表示參與 union 的 select 行id。

          id列

          id列的編號(hào)是 select 的序列號(hào),有幾個(gè) select 就有幾個(gè)id,并且id的順序是按 select 出現(xiàn)的順序增長(zhǎng)的。

          id列越大執(zhí)行優(yōu)先級(jí)越高,id相同則從上往下執(zhí)行,id為NULL最后執(zhí)行

          比如下邊這個(gè)查詢中只有一個(gè)SELECT關(guān)鍵字,所以EXPLAIN的結(jié)果中也就只有一條id列為1的記錄:

          mysql>?EXPLAIN?SELECT?*?FROM?t1?WHERE?key1?=?'e038f672a8';

          對(duì)于連接查詢來說,一個(gè)SELECT關(guān)鍵字后邊的FROM子句中可以跟隨多個(gè)表,所以在連接查詢的執(zhí)行計(jì)劃中,每個(gè)表都會(huì)對(duì)應(yīng)一條記錄,但是這些記錄的id值都是相同的,比如:

          mysql>?EXPLAIN?SELECT?*?FROM?t1?INNER?JOIN?t2;

          可以看到,上述連接查詢中參與連接的t1和t2表分別對(duì)應(yīng)一條記錄,但是這兩條記錄對(duì)應(yīng)的id值都是1。

          注意:

          在連接查詢的執(zhí)行計(jì)劃中,每個(gè)表都會(huì)對(duì)應(yīng)一條記錄,這些記錄的id列的值是相同的,出現(xiàn)在前邊的表表示驅(qū)動(dòng)表,出現(xiàn)在后邊的表表示被驅(qū)動(dòng)表。所以從上邊的EXPLAIN輸出中我們可以看出,查詢優(yōu)化器準(zhǔn)備讓t2表作為驅(qū)動(dòng)表,讓t1表作為被驅(qū)動(dòng)表來執(zhí)行查詢

          對(duì)于包含子查詢的查詢語句來說,就可能涉及多個(gè)SELECT關(guān)鍵字,所以在包含子查詢的查詢語句的執(zhí)行計(jì)劃中,每個(gè)SELECT關(guān)鍵字都會(huì)對(duì)應(yīng)一個(gè)唯一的id值,比如這樣:

          mysql>?EXPLAIN?SELECT?*?FROM?t1?WHERE?key1?IN?(SELECT?key1?FROM?t2)?OR?key3?=?'a1b6cee57a';

          從輸出結(jié)果中我們可以看到,t1表在外層查詢中,外層查詢有一個(gè)獨(dú)立的SELECT關(guān)鍵字,所以第一條記錄的id值就是1,t2表在子查詢中,子查詢有一個(gè)獨(dú)立的SELECT關(guān)鍵字,所以第二條記錄的id值就是2。

          但是這里大家需要特別注意,查詢優(yōu)化器可能對(duì)涉及子查詢的查詢語句進(jìn)行重寫,從而轉(zhuǎn)換為連接查詢。所以如果我們想知道查詢優(yōu)化器對(duì)某個(gè)包含子查詢的語句是否進(jìn)行了重寫,直接查看執(zhí)行計(jì)劃就好了,比如說:

          mysql>?EXPLAIN?SELECT?*?FROM?t1?WHERE?key1?IN?(SELECT?key3?FROM?t2?WHERE?t1.key1?=?'a1b6cee57a');

          可以看到,雖然我們的查詢語句是一個(gè)子查詢,但是執(zhí)行計(jì)劃中t1和t2表對(duì)應(yīng)的記錄的id值全部是1,這就表明了查詢優(yōu)化器將子查詢轉(zhuǎn)換為了連接查詢。

          對(duì)于包含UNION子句的查詢語句來說,每個(gè)SELECT關(guān)鍵字對(duì)應(yīng)一個(gè)id值也是沒錯(cuò)的,不過還是有點(diǎn)兒特別的東西,比方說下邊這個(gè)查詢:

          mysql>?EXPLAIN?SELECT?*?FROM?t1?UNION?SELECT?*?FROM?t2;

          UNION子句是為了把id為1的查詢和id為2的查詢的結(jié)果集合并起來并去重,所以在內(nèi)部創(chuàng)建了一個(gè)名為的臨時(shí)表(就是執(zhí)行計(jì)劃第三條記錄的table列的名稱),id為NULL表明這個(gè)臨時(shí)表是為了合并兩個(gè)查詢的結(jié)果集而創(chuàng)建的。

          跟UNION對(duì)比起來,UNION ALL就不需要為最終的結(jié)果集進(jìn)行去重,它只是單純的把多個(gè)查詢的結(jié)果集中的記錄合并成一個(gè)并返回給用戶,所以也就不需要使用臨時(shí)表。所以在包含UNION ALL子句的查詢的執(zhí)行計(jì)劃中,就沒有那個(gè)id為NULL的記錄,如下所示:

          mysql>?EXPLAIN?SELECT?*?FROM?t1?UNION?ALL?SELECT?*?FROM?t2;

          select_type列

          MySQL每一個(gè)SELECT關(guān)鍵字代表的小查詢都定義了一個(gè)稱之為select_type的屬性,意思是我們只要知道了某個(gè)小查詢的select_type屬性,就知道了這個(gè)小查詢?cè)谡麄€(gè)大查詢中扮演了一個(gè)什么角色

          下面是官方文檔介紹:

          https://dev.mysql.com/doc/refman/5.7/en/explain-output.html#explain_select_type

          SIMPLE

          查詢語句中不包含UNION或者子查詢的查詢都算作是SIMPLE類型,比方說下邊這個(gè)單表查詢的select_type的值就是SIMPLE:

          mysql>?EXPLAIN?SELECT?*?FROM?t1;

          PRIMARY

          對(duì)于包含UNION、UNION ALL或者子查詢的大查詢來說,它是由幾個(gè)小查詢組成的,其中最左邊的那個(gè)查詢的select_type值就是PRIMARY,比方說:

          mysql>?EXPLAIN?SELECT?*?FROM?t1?UNION?SELECT?*?FROM?t2;

          從結(jié)果中可以看到,最左邊的小查詢SELECT * FROM t1對(duì)應(yīng)的是執(zhí)行計(jì)劃中的第一條記錄,它的select_type值就是PRIMARY。

          UNION

          對(duì)于包含UNION或者UNION ALL的大查詢來說,它是由幾個(gè)小查詢組成的,其中除了最左邊的那個(gè)小查詢以外,其余的小查詢的select_type值就是UNION,可以對(duì)比上一個(gè)例子的效果

          UNION RESULT

          MySQL選擇使用臨時(shí)表來完成UNION查詢的去重工作,針對(duì)該臨時(shí)表的查詢的select_type就是UNION RESULT,同樣對(duì)比上面的例子

          SUBQUERY

          如果包含子查詢的查詢語句不能夠轉(zhuǎn)為對(duì)應(yīng)的semi-join的形式,并且該子查詢是不相關(guān)子查詢,并且查詢優(yōu)化器決定采用將該子查詢物化的方案來執(zhí)行該子查詢時(shí),該子查詢的第一個(gè)SELECT關(guān)鍵字代表的那個(gè)查詢的select_type就是SUBQUERY,比如下邊這個(gè)查詢:

          概念解釋:

          semi-join子查詢,是指當(dāng)一張表在另一張表找到匹配的記錄之后,半連接(semi-jion)返回第一張表中的記錄。與條件連接相反,即使在右節(jié)點(diǎn)中找到幾條匹配的記錄,左節(jié)點(diǎn) 的表也只會(huì)返回一條記錄。另外,右節(jié)點(diǎn)的表一條記錄也不會(huì)返回。半連接通常使用IN 或 EXISTS 作為連接條件

          物化:這個(gè)將子查詢結(jié)果集中的記錄保存到臨時(shí)表的過程稱之為物化(Materialize)。那個(gè)存儲(chǔ)子查詢結(jié)果集的臨時(shí)表稱之為物化表。正因?yàn)槲锘碇械挠涗浂冀⒘怂饕ɑ趦?nèi)存的物化表有哈希索引,基于磁盤的有B+樹索引),通過索引執(zhí)行IN語句判斷某個(gè)操作數(shù)在不在子查詢結(jié)果集中變得非常快,從而提升了子查詢語句的性能。

          mysql>?EXPLAIN?SELECT?*?FROM?t1?WHERE?key1?IN?(SELECT?key1?FROM?t2)?OR?key3?=?'a1b6cee57a';

          可以看到,外層查詢的select_type就是PRIMARY,子查詢的select_type就是SUBQUERY。

          DEPENDENT SUBQUERY

          如果包含子查詢的查詢語句不能夠轉(zhuǎn)為對(duì)應(yīng)的semi-join的形式,并且該子查詢是相關(guān)子查詢,則該子查詢的第一個(gè)SELECT關(guān)鍵字代表的那個(gè)查詢的select_type就是DEPENDENT SUBQUERY,比如下邊這個(gè)查詢:

          mysql>?EXPLAIN?SELECT?*?FROM?t1?WHERE?key1?IN?(SELECT?key1?FROM?t2?WHERE?t1.key2?=?t2.key2)?OR?key3?=?'a1b6cee57a';

          DEPENDENT UNION

          在包含UNION或者UNION ALL的大查詢中,如果各個(gè)小查詢都依賴于外層查詢的話,那除了最左邊的那個(gè)小查詢之外,其余的小查詢的select_type的值就是DEPENDENT UNION。比方說下邊這個(gè)查詢:

          mysql>?EXPLAIN?SELECT?*?FROM?t1?WHERE?key1?IN?(SELECT?key1?FROM?t2?WHERE?key1?=?'a1b6cee57a'?UNION?SELECT?key1?FROM?t1?WHERE?key1?=?'a1b6cee57a');

          這個(gè)查詢比較復(fù)雜啊,大查詢里包含了一個(gè)子查詢,子查詢里又是由UNION連起來的兩個(gè)小查詢。從執(zhí)行計(jì)劃中可以看出來,SELECT key1 FROM t2 WHERE key1 = 'a1b6cee57a'這個(gè)小查詢由于是子查詢中第一個(gè)查詢,所以它的select_type是DEPENDENT SUBQUERY,而SELECT key1 FROM t1 WHERE key1 = 'a1b6cee57a'這個(gè)查詢的select_type就是DEPENDENT UNION。

          DERIVED

          對(duì)于采用物化的方式執(zhí)行的包含派生表的查詢,該派生表對(duì)應(yīng)的子查詢的select_type就是DERIVED,比方說下邊這個(gè)查詢:

          mysql>?EXPLAIN?SELECT?*?FROM?(SELECT?key1,?count(*)?as?t?FROM?t1?GROUP?BY?key1)?AS?derived_t1?where?t?>?1;

          從執(zhí)行計(jì)劃中可以看出,id為2的記錄就代表子查詢的執(zhí)行方式,它的select_type是DERIVED,說明該子查詢是以物化的方式執(zhí)行的。id為1的記錄代表外層查詢,大家注意看它的table列顯示的是,表示該查詢是針對(duì)將派生表物化之后的表進(jìn)行查詢的。

          MATERIALIZED

          當(dāng)查詢優(yōu)化器在執(zhí)行包含子查詢的語句時(shí),選擇將子查詢物化之后與外層查詢進(jìn)行連接查詢時(shí),該子查詢對(duì)應(yīng)的select_type屬性就是MATERIALIZED,比如下邊這個(gè)查詢:

          mysql>?EXPLAIN?SELECT?*?FROM?t1?WHERE?key1?IN?(SELECT?key1?FROM?t2);

          執(zhí)行計(jì)劃的第三條記錄的id值為2,說明該條記錄對(duì)應(yīng)的是一個(gè)單表查詢,從它的select_type值為MATERIALIZED可以看出,查詢優(yōu)化器是要把子查詢先轉(zhuǎn)換成物化表。然后看執(zhí)行計(jì)劃的前兩條記錄的id值都為1,說明這兩條記錄對(duì)應(yīng)的表進(jìn)行連接查詢,需要注意的是第二條記錄的table列的值是,說明該表其實(shí)就是id為2對(duì)應(yīng)的子查詢執(zhí)行之后產(chǎn)生的物化表,然后將s1和該物化表進(jìn)行連接查詢。

          type列

          這一列表示關(guān)聯(lián)類型或訪問類型,即MySQL決定如何查找表中的行,查找數(shù)據(jù)行記錄的大概范圍。依次從最優(yōu)到最差分別為:system > const > eq_ref > ref > range > index > ALL一般來說,得保證查詢達(dá)到range級(jí)別,最好達(dá)到ref

          NULL

          mysql能夠在優(yōu)化階段分解查詢語句,在執(zhí)行階段用不著再訪問表或索引。例如:在索引列中選取最小值,可以單獨(dú)查找索引來完成,不需要在執(zhí)行時(shí)訪問表

          mysql>?explain?select?min(id)?from?t1;

          eq_ref

          primary key 或 unique key 索引的所有部分被連接使用 ,最多只會(huì)返回一條符合條件的記錄。這可能是在 const 之外最好的聯(lián)接類型了,簡(jiǎn)單的 select 查詢不會(huì)出現(xiàn)這種 type。

          在連接查詢時(shí),如果被驅(qū)動(dòng)表是通過主鍵或者唯一二級(jí)索引列等值匹配的方式進(jìn)行訪問的(如果該主鍵或者唯一二級(jí)索引是聯(lián)合索引的話,所有的索引列都必須進(jìn)行等值比較),則對(duì)該被驅(qū)動(dòng)表的訪問方法就是eq_ref,比方說:

          mysql>?EXPLAIN?SELECT?*?FROM?t1?INNER?JOIN?t2?ON?t1.id?=?t2.id;

          從執(zhí)行計(jì)劃的結(jié)果中可以看出,MySQL打算將t2作為驅(qū)動(dòng)表,t1作為被驅(qū)動(dòng)表,重點(diǎn)關(guān)注t1的訪問方法是eq_ref,表明在訪問t1表的時(shí)候可以通過主鍵的等值匹配來進(jìn)行訪問。

          ref

          當(dāng)通過普通的二級(jí)索引列與常量進(jìn)行等值匹配時(shí)來查詢某個(gè)表,那么對(duì)該表的訪問方法就可能是ref

          相比?eq_ref,不使用唯一索引,而是使用普通索引或者唯一性索引的部分前綴,索引要和某個(gè)值相比較,可能會(huì)找到多個(gè)符合條件的行。

          mysql>?EXPLAIN?SELECT?*?FROM?t1?WHERE?key1?=?'a';

          可以看到type列的值是ref,表明MySQL即將使用ref訪問方法來執(zhí)行對(duì)t1表的查詢

          system,const

          mysql能對(duì)查詢的某部分進(jìn)行優(yōu)化并將其轉(zhuǎn)化成一個(gè)常量(可以看show warnings 的結(jié)果)。用于 primary key 或 unique key 的所有列與常數(shù)比較時(shí),所以表最多有一個(gè)匹配行,讀取1次,速度比較快。system是const的特例,表里只有一條元組匹配時(shí)為system

          mysql>?EXPLAIN?SELECT?*?FROM?t1?WHERE?id?=?5;

          ref_or_null

          當(dāng)對(duì)普通二級(jí)索引進(jìn)行等值匹配查詢,該索引列的值也可以是NULL值時(shí),那么對(duì)該表的訪問方法就可能是ref_or_null,比如說:

          mysql>?EXPLAIN?SELECT?*?FROM?t1?WHERE?key1?=?'a'?OR?key1?IS?NULL;

          index_merge

          一般情況下對(duì)于某個(gè)表的查詢只能使用到一個(gè)索引,但在某些場(chǎng)景下可以使用多種索引合并的方式來執(zhí)行查詢,我們看一下執(zhí)行計(jì)劃中是怎么體現(xiàn)MySQL使用索引合并的方式來對(duì)某個(gè)表執(zhí)行查詢的:

          mysql>?EXPLAIN?SELECT?*?FROM?t1?WHERE?key1?=?'a'?OR?key2?=?'a';

          從執(zhí)行計(jì)劃的type列的值是index_merge就可以看出,MySQL打算使用索引合并的方式來執(zhí)行對(duì)t1表的查詢。

          unique_subquery

          類似于兩表連接中被驅(qū)動(dòng)表的eq_ref訪問方法,unique_subquery是針對(duì)在一些包含IN子查詢的查詢語句中,如果查詢優(yōu)化器決定將IN子查詢轉(zhuǎn)換為EXISTS子查詢,而且子查詢可以使用到主鍵進(jìn)行等值匹配的話,那么該子查詢執(zhí)行計(jì)劃的type列的值就是unique_subquery,比如下邊的這個(gè)查詢語句:

          mysql>?EXPLAIN?SELECT?*?FROM?t1?WHERE?key2?IN?(SELECT?id?FROM?t2?where?t1.key1?=?t2.key1)?OR?key3?=?'a';

          可以看到執(zhí)行計(jì)劃的第二條記錄的type值就是unique_subquery,說明在執(zhí)行子查詢時(shí)會(huì)使用到id列的索引。

          range

          范圍掃描通常出現(xiàn)在 in(), between ,> ,<, >= 等操作中。使用一個(gè)索引來檢索給定范圍的行。

          mysql>?EXPLAIN?SELECT?*?FROM?t1?WHERE?key1?IN?('a',?'b',?'c');

          index

          當(dāng)我們可以使用索引覆蓋,但需要掃描全部的索引記錄時(shí),該表的訪問方法就是index

          掃描全表索引,這通常比ALL快一些。(index是從索引中讀取的,而all是從硬盤中讀取)

          ALL

          最熟悉的全表掃描

          mysql>?explain?select?*?from?t2;

          一般來說,這些訪問方法按照我們介紹它們的順序性能依次變差。其中除了All這個(gè)訪問方法外,其余的訪問方法都能用到索引,除了index_merge訪問方法外,其余的訪問方法都最多只能用到一個(gè)索引。

          possible_keys和key列

          possible_keys列顯示查詢可能使用哪些索引來查找。

          explain 時(shí)可能出現(xiàn)?possible_keys?有列,而 key 顯示 NULL 的情況,這種情況是因?yàn)楸碇袛?shù)據(jù)不多,mysql認(rèn)為索引對(duì)此查詢幫助不大,選擇了全表查詢。

          如果possible_keys列是NULL,則沒有相關(guān)的索引。在這種情況下,可以通過檢查 where 子句看是否可以創(chuàng)造一個(gè)適當(dāng)?shù)乃饕齺硖岣卟樵冃阅埽缓笥?explain 查看效果。

          key列顯示mysql實(shí)際采用哪個(gè)索引來優(yōu)化對(duì)該表的訪問。如果沒有使用索引,則該列是 NULL。如果想強(qiáng)制mysql使用或忽視possible_keys列中的索引,在查詢中使用 force index、ignore index。

          比方說下邊這個(gè)查詢:

          mysql>?EXPLAIN?SELECT?*?FROM?t1?WHERE?key1?>?'z'?AND?key2?=?'a';

          上述執(zhí)行計(jì)劃的possible_keys列的值是idx_key1,idx_key2_key3,表示該查詢可能使用到idx_key1,idx_key2_key3兩個(gè)索引,然后key列的值是idx_key3,表示經(jīng)過查詢優(yōu)化器計(jì)算使用不同索引的成本后,最后決定使用idx_key3來執(zhí)行查詢比較劃算。

          需要注意的一點(diǎn)是,possible_keys列中的值并不是越多越好,可能使用的索引越多,查詢優(yōu)化器計(jì)算查詢成本時(shí)就得花費(fèi)更長(zhǎng)時(shí)間,所以如果可以的話,盡量刪除那些用不到的索引。

          key_len列

          這一列顯示了mysql在索引里使用的字節(jié)數(shù),通過這個(gè)值可以算出具體使用了索引中的哪些列

          對(duì)于使用固定長(zhǎng)度類型的索引列來說,它實(shí)際占用的存儲(chǔ)空間的最大長(zhǎng)度就是該固定值,對(duì)于指定字符集的變長(zhǎng)類型的索引列來說,比如某個(gè)索引列的類型是VARCHAR(100),使用的字符集是utf8,那么該列實(shí)際占用的最大存儲(chǔ)空間就是100 × 3 = 300個(gè)字節(jié)。

          如果該索引列可以存儲(chǔ)NULL值,則key_len比不可以存儲(chǔ)NULL值時(shí)多1個(gè)字節(jié)。

          對(duì)于變長(zhǎng)字段來說,都會(huì)有2個(gè)字節(jié)的空間來存儲(chǔ)該變長(zhǎng)列的實(shí)際長(zhǎng)度。

          當(dāng)字符串過長(zhǎng)時(shí),mysql會(huì)做一個(gè)類似左前綴索引的處理,將前半部分的字符提取出來做索引。

          key_len計(jì)算規(guī)則如下:字符串 char(n):n字節(jié)長(zhǎng)度 varchar(n):2字節(jié)存儲(chǔ)字符串長(zhǎng)度,如果是utf-8,則長(zhǎng)度 3n + 2 數(shù)值類型 tinyint:1字節(jié) smallint:2字節(jié) int:4字節(jié) bigint:8字節(jié)   時(shí)間類型  date:3字節(jié) timestamp:4字節(jié) datetime:8字節(jié)

          比如下邊這個(gè)查詢:

          mysql>?EXPLAIN?SELECT?*?FROM?s1?WHERE?id?=?5;

          由于id列的類型是INT,并且不可以存儲(chǔ)NULL值,所以在使用該列的索引時(shí)key_len大小就是4。

          對(duì)于可變長(zhǎng)度的索引列來說,比如下邊這個(gè)查詢:

          mysql>?EXPLAIN?SELECT?*?FROM?t1?WHERE?key1?=?'a';

          由于key1列的類型是VARCHAR(100),所以該列實(shí)際最多占用的存儲(chǔ)空間就是300字節(jié),又因?yàn)樵摿性试S存儲(chǔ)NULL值,所以key_len需要加1,又因?yàn)樵摿惺强勺冮L(zhǎng)度列,所以key_len需要加2,所以最后ken_len的值就是303。

          rows列

          這一列是mysql估計(jì)要讀取并檢測(cè)的行數(shù),注意這個(gè)不是結(jié)果集里的行數(shù)。

          如果查詢優(yōu)化器決定使用全表掃描的方式對(duì)某個(gè)表執(zhí)行查詢時(shí),執(zhí)行計(jì)劃的rows列就代表預(yù)計(jì)需要掃描的行數(shù),如果使用索引來執(zhí)行查詢時(shí),執(zhí)行計(jì)劃的rows列就代表預(yù)計(jì)掃描的索引記錄行數(shù)。比如下邊這個(gè)查詢:

          mysql>?EXPLAIN?SELECT?*?FROM?t1?WHERE?key1?>?'a';

          我們看到執(zhí)行計(jì)劃的rows列的值是113,這意味著查詢優(yōu)化器在經(jīng)過分析使用idx_key1進(jìn)行查詢的成本之后,覺得滿足key1 > 'a'這個(gè)條件的記錄只有113條。

          ref列

          這一列顯示了在key列記錄的索引中,表查找值所用到的列或常量,常見的有:const(常量),字段名(例:t1.id

          ref列展示的就是與索引列作等值匹配的值什么,比如只是一個(gè)常數(shù)或者是某個(gè)列。大家看下邊這個(gè)查詢:

          mysql>?EXPLAIN?SELECT?*?FROM?t1?WHERE?key1?=?'a';

          可以看到ref列的值是const,表明在使用idx_key1索引執(zhí)行查詢時(shí),與key1列作等值匹配的對(duì)象是一個(gè)常數(shù),當(dāng)然有時(shí)候更復(fù)雜一點(diǎn):

          mysql>?EXPLAIN?SELECT?*?FROM?t1?INNER?JOIN?t2?ON?t1.id?=?t2.id;

          可以看到對(duì)被驅(qū)動(dòng)表t1的訪問方法是eq_ref,而對(duì)應(yīng)的ref列的值是canal_manager.t2.id,這說明在對(duì)被驅(qū)動(dòng)表進(jìn)行訪問時(shí)會(huì)用到PRIMARY索引,也就是聚簇索引與一個(gè)列進(jìn)行等值匹配的條件,于t2表的id作等值匹配的對(duì)象就是canal_manager.t2.id列(注意這里把數(shù)據(jù)庫(kù)名也寫出來了)。

          有的時(shí)候與索引列進(jìn)行等值匹配的對(duì)象是一個(gè)函數(shù),比方說下邊這個(gè)查詢

          mysql>?EXPLAIN?SELECT?*?FROM?t1?INNER?JOIN?t2?ON?t2.key1?=?UPPER(t1.key1);

          我們看執(zhí)行計(jì)劃的第二條記錄,可以看到對(duì)t2表采用ref訪問方法執(zhí)行查詢,然后在查詢計(jì)劃的ref列里輸出的是func,說明與t2表的key1列進(jìn)行等值匹配的對(duì)象是一個(gè)函數(shù)。

          Extra列

          顧名思義,Extra列是用來說明一些額外信息的,我們可以通過這些額外信息來更準(zhǔn)確的理解MySQL到底將如何執(zhí)行給定的查詢語句。

          Using index

          查詢的列被索引覆蓋,并且where篩選條件是索引的前導(dǎo)列,是性能高的表現(xiàn)。一般是使用了覆蓋索引(索引包含了所有查詢的字段)。對(duì)于innodb來說,如果是輔助索引性能會(huì)有不少提高

          mysql>?EXPLAIN?SELECT?key1?FROM?t1?WHERE?key1?=?'a';

          Using where

          當(dāng)我們使用全表掃描來執(zhí)行對(duì)某個(gè)表的查詢,并且該語句的WHERE子句中有針對(duì)該表的搜索條件時(shí),在Extra列中會(huì)提示上述額外信息。比如下邊這個(gè)查詢

          mysql>?EXPLAIN?SELECT?*?FROM?t1?WHERE?name=?'a1b6cee57a';

          Using where Using index

          查詢的列被索引覆蓋,并且where篩選條件是索引列之一但是不是索引的前導(dǎo)列,意味著無法直接通過索引查找來查詢到符合條件的數(shù)據(jù)

          mysql>?EXPLAIN?SELECT?id?FROM?t1?WHERE?key3=?'a1b6cee57a';

          NULL

          查詢的列未被索引覆蓋,并且where篩選條件是索引的前導(dǎo)列,意味著用到了索引,但是部分字段未被索引覆蓋,必須通過“回表”來實(shí)現(xiàn),不是純粹地用到了索引,也不是完全沒用到索引

          mysql>?EXPLAIN?SELECT?*?FROM?t1?WHERE?key2=?'a1b6cee57a';

          Using index condition

          與Using where類似,查詢的列不完全被索引覆蓋,where條件中是一個(gè)前導(dǎo)列的范圍;

          mysql>??EXPLAIN?SELECT?*?FROM?t1?WHERE?key1?like?'1';

          Using temporary

          在許多查詢的執(zhí)行過程中,MySQL可能會(huì)借助臨時(shí)表來完成一些功能,比如去重、排序之類的,比如我們?cè)趫?zhí)行許多包含DISTINCT、GROUP BY、UNION等子句的查詢過程中,如果不能有效利用索引來完成查詢,MySQL很有可能尋求通過建立內(nèi)部的臨時(shí)表來執(zhí)行查詢。如果查詢中使用到了內(nèi)部的臨時(shí)表,在執(zhí)行計(jì)劃的Extra列將會(huì)顯示Using temporary提示,比方說這樣:

          name沒有索引,此時(shí)創(chuàng)建了張臨時(shí)表來distinct

          mysql>?explain?select?distinct?name?from?t1;

          key1建立了idx_key1索引,此時(shí)查詢時(shí)extra是using index,沒有用臨時(shí)表

          mysql>?explain?select?distinct?key1?from?t1;

          Using filesort

          mysql 會(huì)對(duì)結(jié)果使用一個(gè)外部索引排序,而不是按索引次序從表里讀取行。此時(shí)mysql會(huì)根據(jù)聯(lián)接類型瀏覽所有符合條件的記錄,并保存排序關(guān)鍵字和行指針,然后排序關(guān)鍵字并按順序檢索行信息。這種情況下一般也是要考慮使用索引來優(yōu)化的。

          name未創(chuàng)建索引,會(huì)瀏覽t1整個(gè)表,保存排序關(guān)鍵字name和對(duì)應(yīng)的id,然后排序name并檢索行記錄

          mysql>?explain?select?*?from?t1?order?by?name;

          key1建立了idx_key1索引,此時(shí)查詢時(shí)extra是using index

          mysql>?explain?select?*?from?t1?order?by?key1;

          Using join buffer (Block Nested Loop)

          在連接查詢執(zhí)行過程中,當(dāng)被驅(qū)動(dòng)表不能有效的利用索引加快訪問速度,MySQL一般會(huì)為其分配一塊名叫join buffer的內(nèi)存塊來加快查詢速度,也就是我們所講的基于塊的嵌套循環(huán)算法,比如下邊這個(gè)查詢語句:

          mysql>?EXPLAIN?SELECT?*?FROM?t1?INNER?JOIN?t2?ON?t1.key3?=?t2.key3;

          No tables used

          當(dāng)查詢語句的沒有FROM子句時(shí)將會(huì)提示該額外信息,比如:

          mysql>?EXPLAIN?SELECT?1;

          Impossible WHERE

          查詢語句的WHERE子句永遠(yuǎn)為FALSE時(shí)將會(huì)提示該額外信息,比方說:

          mysql>?EXPLAIN?SELECT?*?FROM?t1?WHERE?1?!=?1;

          參考:

          https://dev.mysql.com/doc/refman/5.7/en/explain-output.html#explain-extra-information


          往期推薦

          前瞻:在 Java 16 中會(huì)帶來哪些新特性?

          高可用 Prometheus 的常見問題

          Fastjson < 1.2.68版本反序列化漏洞分析篇

          音效摸魚還不夠爽?試試IDE里打幾盤魂斗羅?

          一個(gè)讓你敲代碼的同時(shí),找回童年樂趣的 IntelliJ 插件


          掃一掃,關(guān)注我

          一起學(xué)習(xí),一起進(jìn)步

          每周贈(zèng)書,福利不斷

          深度內(nèi)容

          推薦加入


          最近熱門內(nèi)容回顧? ?#技術(shù)人系列


          瀏覽 75
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  在线免费观看黄色视频 | 成人毛片女人18女人 | 亚洲视频中文字幕在线观看 | 日本最黄色片特一级生活片 | 色就是色setufree |