MySQL EXPLAIN 列說明 原

寫在前面

想要進行 MySQL SQL 語句的優化 Explain 是一定要掌握的。應用驅動學習。參考 MySQL 官方文檔 :https://dev.mysql.com/doc/refman/8.0/en/explain-output.html

SQL 準備 :

DROP TABLE IF EXISTS student;
CREATE TABLE `student` (
  id INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  name VARCHAR(30) NOT NULL COMMENT '姓名' ,
  birthday VARCHAR(30) NOT NULL COMMENT '生日' ,
  sex VARCHAR(10) NOT NULL COMMENT '性別' ,
  PRIMARY KEY (id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='學生表';
INSERT INTO student VALUES
(NULL , '趙雷' , '1990-01-01' , '男') ,
(NULL , '錢電' , '1990-12-21' , '男') ,
(NULL , '孫風' , '1990-05-20' , '男') ,
(NULL , '李雲' , '1990-08-06' , '男') ,
(NULL , '周梅' , '1991-12-01' , '女') ,
(NULL , '吳蘭' , '1992-03-01' , '女') ,
(NULL , '鄭竹' , '1989-07-01' , '女') ,
(NULL , '王菊' , '1990-01-20' , '女');

DROP TABLE IF EXISTS course;
CREATE TABLE course(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主鍵' ,
  name VARCHAR(30) NOT NULL COMMENT '課程名稱' ,
  teacher_id INT UNSIGNED NOT NULL COMMENT '教師ID' ,
  PRIMARY KEY (id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='課程表';
INSERT INTO course VALUES
(NULL , N'語文' , 1) ,
(NULL  , N'數學' , 2) ,
(NULL  , N'英語' , 3);

DROP TABLE IF EXISTS teacher;
CREATE TABLE teacher(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主鍵' ,
  name VARCHAR(30) NOT NULL COMMENT '姓名' ,
  PRIMARY KEY (id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='教師表';
INSERT INTO teacher VALUES
(NULL , '張三') ,
(NULL , '李四') ,
(NULL , '王五');

DROP TABLE IF EXISTS score;
CREATE TABLE score(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主鍵' ,
  student_id INT UNSIGNED NOT NULL COMMENT '學生ID' ,
  course_id INT UNSIGNED NOT NULL COMMENT '課程ID' ,
  score DECIMAL UNSIGNED DEFAULT 0 COMMENT '成績' ,
  PRIMARY KEY (id)
)ENGINE = innoDB DEFAULT CHARSET = utf8 COMMENT '成績表';
INSERT INTO score(student_id, course_id,score) VALUES
(1 , 1 , 80) ,
(1 , 2 , 90) ,
(1 , 3 , 99) ,
(2 , 1 , 70) ,
(2 , 2 , 60) ,
(2 , 3 , 80) ,
(3 , 1 , 80) ,
(3 , 2 , 80) ,
(3 , 3 , 80) ,
(4 , 1 , 50) ,
(4 , 2 , 33) ,
(4 , 3 , 20) ,
(5 , 1 , 76) ,
(5 , 2 , 87) ,
(5 , 3 , 31.5) ,
(6 , 1 , 34) ,
(6 , 2 , 89) ,
(6 , 3 , 98) ;

Explain 輸出的列

id :  查詢標識符,表示 SQL 語句中執行 select 子句或者是操作的順序。

1. id 相同時執行順序從上至下。

2. id 不同時 , 如果是子查詢 ,id 的序號會遞增, 序號越大的越先執行。

3. id 相同,不同都存在時,id 相同的可以認爲是一組查詢按從上至下的順序執行。id 值越大越優先執行。

4. id 爲 NULL , 如果行引用其他行的聯合結果,則值可以爲NULL。在這種情況下,表列顯示像<unionM,N>這樣的值,以指示該行引用id值爲M和N的行的並。

select_type : 查詢的類型,有 11 種

1. SIMPLE :簡單的查詢沒有使用 UNION 或者是子查詢 。

select * from student ;
select * from student where name = '趙雷';

2. PRIMARY : 最外層的查詢類型。

select * , 
(select name from teacher where id = teacher_id) as teacher_name
from course ;

3. UNION :第二個或者是在 "UNION" 關鍵字之後的 select 語句。

select * from course
left join score
on course.id = score.course_id
where course.name = '語文'
union
select * from course
left join score
on course.id = score.course_id
where course.name = '數學' ;

4. DEPENDENT UNION :第二個或者是在 "UNION" 關鍵字之後的 select 語句,依賴外層查詢。

5. UNION RESULT :兩個查詢結果集合並後的結果集。

select * from course
left join score
on course.id = score.course_id
where course.name = '語文'
union
select * from course
left join score
on course.id = score.course_id
where course.name = '數學' ;

6. SUBQUERY :子查詢中第一個 select 語句。

select * ,
(select name from teacher where id = 2) as teacher_name
from course ;

7. DEPENDENT SUBQUERY : 子查詢中第一個 select 語句,依賴外層查詢。

select * ,
(select name from teacher where id = teacher_id) as teacher_name
from course ;

8. DERIVED :  衍生表。

9. MATERIALIZED :具體的子查詢。

10. UNCACHEABLE SUBQUERY :無法緩存結果的子查詢,必須對外部查詢的每行重新進行評估。

11. UNCACHEABLE UNION : 第二個或者是在 "UNION" 關鍵字之後的 select 語句 , 無法緩存結果的子查詢。

 

table : 對應行正在訪問哪一個表,表名或者別名

關聯優化器會爲查詢選擇關聯順序,左側深度優先當 from 中有子查詢的時候,table 是 derivedN 的形式, N 指向子查詢,就是 explain 結果中的那一列。當 select_type 是 union result 的時候 ,table 是 “union 1 ,2” 這樣的形勢 ,1 ,2 表示 explain 結果中的 id 。注意:MySQL 對待這些表和普通表一樣,但是這些“臨時表”是沒有任何索引的。

select * from course
left join score
on course.id = score.course_id
where course.name = '語文'
union
select * from course
left join score
on course.id = score.course_id
where course.name = '數學' ;

最後一行的 table 是 <union1,2> ,  這裏的 1 和 2 ,就是圖中 id = 1 和 id = 2 的行。

partitions :將由查詢匹配記錄的分區。未分區表的值爲NULL。

type :對錶的訪問類型 , 有 12 種類型從最好到最糟的順序如下 :

system :這個表中只有一條記錄,這是 const 類型的特殊情況。

const : 該表最多有一個匹配行,它在查詢開始時被讀取。因爲只有一行,所以該行中的列的值可以被優化器的其餘部分視爲常量。const表非常快,因爲它們只讀一次。

像是這種用主鍵或者唯一性索引能夠唯一定位一條記錄的就是 const 類型。

select * from student where id = 2 ;

eq_ref : 最多隻返回一條符合條件的記錄 ,當使用主鍵或者是唯一性非NULL索引時產生。

ref : 一種索引訪問,返回所有匹配某個單個值的行。此類索引訪問只有當使用非唯一性索引或唯一性索引非唯一性前綴時纔會發生。這個類型和eq_ref 不同的是,它用在關聯操作只使用了索引的最左前綴,或者索引不是唯一的和主鍵索引。ref 可以用於使用 < ,= ,> 操作符帶索引的列。

full_text : 使用到了 full text 索引。

ref_or_null : 類似於 ref 但是MySQL對包含 NULL 值的行進行了特殊的搜索。

index_merge :  表示使用到了索引合併優化,在這種情況下,輸出行中的鍵列包含使用的索引列表,key_len包含所使用的索引的最長鍵部分的列表。

unique_subquery : 這種類型取代了 eq_ref 在一些子查詢中,類似 :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 : 只有在指定範圍內的行被檢索,使用索引來進行查找。explain 結果中的 key 列顯示使用了那個索引 。當使用了 = ,< , > , <> , <= , >= , between , like ,  in() 這些操作符的時候產生。

index :全索引掃描 ,掃描全表的時候按照索引的順序而不是按照行進行掃描。如果索引是查詢的覆蓋索引,並且可以用於滿足表中所需的所有數據,則只掃描索引樹。如果沒有發生索引覆蓋則還需要回行到磁盤上查找數據。

ALL : 在磁盤上對錶進行全表掃描。

NULL : MySQL能在優化階段分解查詢語句,在執行階段甚至用不到訪問表或索引(高效)。

possible_keys :  有可能使用到的索引。

key : 實際使用到的索引。

key_len : 使用到的索引所佔的字節數。

ref : 顯示了之前的表在key列記錄的索引中查找值所用的列或常量。

rows : 爲了找到所需的行而需要讀取的行數,估算值。

filtered : 由表條件過濾的錶行的估計百分比。最大值爲100,這意味着沒有發生行過濾。值從100下降表明過濾量增加。

 

Extra :  額外的信息:

Using filesort : 說明MySQL需要對數據進行額外的排序操作,不能通過索引順序來進行排序,這個操作比較消耗CPU資源。

Using temporary :  使用了臨時表保存中間結果,MySQL在對查詢結果排序時使用了臨時表。常見於 order by , group by , join 操作。

Using index : 發生了索引覆蓋 , 查詢時在索引樹上取到了需要查詢的數據,不需要再進行回行操作。

Using join buffer : 使用了連接緩存:Block Nested Loop,連接算法是塊嵌套循環連接;Batched Key Access,連接算法是批量索引連接。

Using where : 使用了WHERE從句來限制哪些行將與下一張表匹配或者是返回給用戶。注意:Extra列出現Using where表示MySQL服務器將存儲引擎返回服務層以後再應用WHERE條件過濾。

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

 

 

 

 

 

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