mysql閱讀查詢執行計劃的簡要說明

學習數據庫查詢優化技術,第一步需要看明白查詢執行計劃,根據查詢執行計劃理解查詢優化器的執行過程,體會優化技術的運用情況。所以,讀懂查詢執行計劃是掌握查詢優化技術的必要條件。

         以下從MySQL查詢執行計劃的格式和關鍵字,介紹MySQL的查詢執行計劃,並結合實例,幫助讀者理解查詢執行計劃。


         示例  演示如何閱讀MySQL的查詢執行計劃。先創建5張表,命令如下(各表的數據量爲:t1表10000行數據,t2表100行數據,t3表100行數據,t4表7行數據,t5表10行數據):

CREATE TABLE t1(id1 INT,a1 INT,b1INT,PRIMARY KEY(id1));

CREATE TABLE t2(id2 INT,a2 INT,b2 INT);

CREATE TABLE t3(id3 INT UNIQUE,a3 INT,b3INT);

CREATE TABLE t4(id4 INT,a4 INT,b4 INT);

CREATE TABLE t5(id5 INT UNIQUE,a5 INT,b5INT);

 

          使用下面的存儲過程插入表中的數據:

DELIMITER // 

CREATE PROCEDURE proc01() 

begin

declare var int; 

set var=0; 

while var<1000 do 

insert into t1 values(var,var,var); 

set var=var+1; 

end while; 

end; 

// 

DELIMITER ;

        注:具體的測試環境搭建過程,我在另一個博客中有所描述,可以參考。


MySQL的查詢執行計劃解釋

 

MySQL 5.6.10 版本使用Explain類表示查詢執行計劃。通過EXPLAIN這個SQL語句觸發,顯示查詢執行計劃。

1.     EXPLAIN功能

語法格式:

EXPLAN [explain_type] explainable_stmt

可選項包括:

EXTENDED | PARTITIONS | FORMAT=format_name

Format_name:

TRADITIONAL |JSON

 

說明:

EXPLAIN命令:顯示SQL語句的查詢執行計劃。

EXPLAIN EXTENDED命令:顯示SQL語句的詳細的查詢執行計劃;之後可以通過 show warnings命令查看詳細的信息。

EXPLAIN PARTITIONS命令:顯示SQL語句的帶有分區表信息的查詢執行計劃。

EXPLAIN命令:輸出格式有以下兩種:

TRADITIONAL:傳統類型;按行隔離,每行標識一個子操作。

JSON:JSON格式。

Explainable_stmt:可被EXPLAIN執行的SQL語句,包括的類型有:select、insert、update、delete。

 

2.     查詢執行計劃

理解MySQL查詢執行計劃,需要理解執行順序和結點解析兩個部分。

 

1)   執行順序

執行5表連接的查詢語句,演示MySQL的查詢執行計劃樣式,語句如下:

[html] view plain copy
  1. EXPLAIN SELECT * FROM (t1 LEFT JOIN t2 ON true),(t3 FULL JOIN t4 ON true),t5 WHERE id1=id2 AND id2=id3 AND id3=id4 AND id4=id5;  

 

執行SQL,結果如下所示:

[html] view plain copy
  1.  EXPLAIN SELECT * FROM (t1 LEFT JOIN t2 ON true),(t3 FULL JOIN t4 ON true),t5 WHERE id1=id2 AND id2=id3 AND id3=id4 AND id4=id5;  
  2. +----+-------------+-------+--------+---------------+---------+---------+-------------+------+----------------------------------------------------+  
  3. | id | select_type | table | type   | possible_keys | key     | key_len | ref         | rows | Extra                                              |  
  4. +----+-------------+-------+--------+---------------+---------+---------+-------------+------+----------------------------------------------------+  
  5. |  1 | SIMPLE      | t2    | ALL    | NULL          | NULL    | NULL    | NULL        |  192 | Using where                                        |  
  6. |  1 | SIMPLE      | FULL  | ref    | id3           | id3     | 5       | test.t2.id2 |    1 | NULL                                               |  
  7. |  1 | SIMPLE      | t5    | ref    | id5           | id5     | 5       | test.t2.id2 |    1 | NULL                                               |  
  8. |  1 | SIMPLE      | t1    | eq_ref | PRIMARY       | PRIMARY | 4       | test.t2.id2 |    1 | NULL                                               |  
  9. |  1 | SIMPLE      | t4    | ALL    | NULL          | NULL    | NULL    | NULL        |  400 | Using where; Using join buffer (Block Nested Loop) |  
  10. +----+-------------+-------+--------+---------------+---------+---------+-------------+------+----------------------------------------------------+  
  11. 5 rows in set (0.00 sec)  

[html] view plain copy
  1. > EXPLAIN SELECT * FROM (t1 LEFT JOIN t2 ON true),(t3 FULL JOIN t4 ON true),t5 WHERE id1=id2 AND id2=id3 AND id3=id4 AND id4=id5;  
  2. +----+-------------+-------+--------+---------------+---------+---------+-------------+------+----------------------------------------------------+  
  3. | id | select_type | table | type   | possible_keys | key     | key_len | ref         | rows | Extra                                              |  
  4. +----+-------------+-------+--------+---------------+---------+---------+-------------+------+----------------------------------------------------+  
  5. |  1 | SIMPLE      | t4    | ALL    | NULL          | NULL    | NULL    | NULL        |    7 | Using where                                        |  
  6. |  1 | SIMPLE      | FULL  | ref    | id3           | id3     | 5       | test.t4.id4 |    1 | NULL                                               |  
  7. |  1 | SIMPLE      | t5    | ref    | id5           | id5     | 5       | test.t4.id4 |    1 | NULL                                               |  
  8. |  1 | SIMPLE      | t1    | eq_ref | PRIMARY       | PRIMARY | 4       | test.t4.id4 |    1 | NULL                                               |  
  9. |  1 | SIMPLE      | t2    | ALL    | NULL          | NULL    | NULL    | NULL        |  100 | Using where; Using join buffer (Block Nested Loop) |  
  10. +----+-------------+-------+--------+---------------+---------+---------+-------------+------+----------------------------------------------------+  
  11. 5 rows in set (0.00 sec)  

下面對該執行結果進行簡要分析:

從第1行到第9行,表示了完成的查詢計劃;

第1行到第3行,表明查詢計劃的結構;id表示對象被操作的順序;ID值大,先被執行;如果相同,執行順序從上到下;

從第4行起,每一行爲一個結點,表示本結點被操作對象的可用信息,如索引等;

表的連接次序爲:t4,t5,t3,t1,t2.這和初始給定的連接次序不同,經過優化,外連接被消除;

T4表的元組數最少,安裝mysql多表連接算法,表經過排序後,順序爲t4,t5,t2,t3,t1.

因爲t5,t3,t1上有索引可以利用,所以t4上的一條元組確定後,則額可以利用索引之間定位t5,t3,t1表上的元組,所以第5,6,7行的key列又索引可用;ref列表明瞭這3個表都是引用了t4表的id4列。

t2表的數據相對較多,且又沒有索引,最後被連接,連接使用了Extra列表明的嵌套循環連接算法,並且使用了連接緩存。

 

2)   結點解析

MySQL查詢計劃的輸出列的含義如下:

id:每個被獨立執行的操作的標識,表示對象被操作的順序;ID值大,先被執行;如果相同,執行順序從上到下;

select_type:查詢每個select子句中的類型;具體值如下表所示;

table:名字,被操作的對象名稱,通常是表明,但又其他格式。

partitions:匹配的分區信息(對於非分區表值爲NULL)

type:連接操作的類型;具體值見後面的表格;

possible_keys:備選的索引(列出可能被使用到的索引)

key:經過優化器選定的索引;常用analyzetable命令,可以使優化器正確地選擇索引。

key_len:被優化器選定的索引鍵的長度,單位是字節。

ref:表示本行被操作的對象的參照對象(被參照的對象可能是一個常量用const表示,也可能是其他表的key指向的對象)。

rows:查詢執行所掃描的元組個數(對於InnoDB,此值是估計值)。

filtered:安裝條件表上數據被元組過濾的元組個數的百分比,rows*filetered/100可以求出過濾後的元組數即實際的元組數。

extra:MySQL查詢優化器執行查詢過程中對查詢計劃的重要補充信息。

 

MySQL查詢執行計劃select_type列子句類型表

Select_type

說明

SIMPLE

簡單的select語句(不包括UNION操作或子查詢操作)

PRIMARY

查詢中最外層的select(如兩表做UNION或存在有子查詢,外層的表被稱作primary,內層被作爲UNION)

UNION

UNION操作中,查詢中處於內層的select(內存的select語句與外層的select語句沒有依賴關係)

DEPENDENT UNION

UNION操作中,查詢中處於內層的select(內存的select語句與外層的select語句有依賴關係)

UNION RESULT

UNION操作的結果,ID通常爲NULL

SUBQUERY

子查詢中的首個select(如果有多個子查詢存在)

DEPENDENT SUBQUERY

子查詢中的首個select,但依賴於外層的表(如果有多個子查詢存在)

DERIVED

被驅動的select子查詢(子查詢位於from子句)

MATERIALIZED

被物化的子查詢

UNCACHEABLE SUBQUERY

對於外層的主表,子查詢不可被物化,每次都需要計算(耗時操作)

UNCACHEABLE UNION

UNION操作中,內層的不可物化的子查詢(類似於UNCACHEABLE SUBQUERY)

 

連接操作數據訪問方式表

代碼表示方式

說明

JT_SYSSTEM

常量表情況一,表上只有一條元組匹配

JT_COUNST

常量表情況二,where條件篩選後表上至多有一條元組匹配,如:where table.pk=2(pk列是主鍵列,值爲2的要麼有一條,要麼沒有)

JT_EQ_REF

參與連接運算的表,是內表(在嗲嗎實現的算法中,兩表連接時作爲循環中的內循環遍歷對象,這樣的表爲內表)。基於索引(連接字段上存在唯一索引或主機索引,且操作符必須是“=”謂詞,索引的值不能爲NULL)做掃描,使得對外表的一條元組,內表只有唯一一條元組與之對應

JT_REF

可用於單表索引或連接。參與連接運算的表,是內表。基於索引(連接字段上的索引是非唯一索引,操作符必須是“=”謂詞,連接字段值不可爲NULL)做掃描,是的對外表的一條元組,內表可有若干條元組與之對應

JT_REF_OR_NULL

類似ref,只是搜索條件敖闊:連接字段的值可爲NULL的情況,如:where col=… or col IS NULL

JT_RANGE

範圍掃描。基於索引做範圍掃描,爲諸如 BETWEEN,IN,>=,like類操作提供支持

JT_INDEX_SCAN

索引做掃描。是基於索引在索引的葉子結點上找滿足條件的數據(不需要訪問數據文件)

JT_ALL

全表掃描或範圍掃描;不使用索引,順序掃描,直接讀取表上的數據(訪問數據文件)

JT_UNIQUE_SUBQUERY

在子查詢中,基於唯一索引進行掃描。類似於eq_ref

JT_INDEX_SUBQUERY

在子查詢中,基於除唯一索引之外的索引進行掃描

JT_INDEX_MERGE

多重範圍掃描,兩表連接的每個表的連接字段上均有索引存在且索引有序,結果合併在一起。適用於做集合的並、交操作

JT_FT

FT,FullText,全文檢索

 

 

Extra信息解釋表

Extra值

說明

Child of ‘table’ pushed join@l

MySQL cluster使用的參數。表示在連接操作中某個表被下推到NDB引擎的某個結點上執行

Const row not found

在連接中,查詢一個沒有元組的空表

Deleting all rows

對於刪除操作,某些存儲引擎支持快速刪除數據

Distinct

優化distinct操作,在找到第一匹配的元組後即停止找同樣值的動作

FirstMatch(tb1_name)

半連接算法中對錶採取了受此匹配的連接策略

Full scan on NULL key

子查詢中,優化器不能使用基於索引的訪問方式時(因有空值存在)所採取的一種數據訪問策略

Impossible HAVING

Having的子句值總是FALSE(不能獲取任何元組)

Impossible WHERE

Where子句的值總是FALSE(不能獲取任何元組)

Materialize,Scan

MySQL 5.6.7版本之前,表示使用單一被物化的臨時表;之後的版本,物化是通過select_type列表達的

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章