想要進行 MySQL SQL 語句的優化 Explain 是必定要掌握的。應用驅動學習。參考 MySQL 官方文檔 :https://dev.mysql.com/doc/refman/8.0/en/explain-output.htmlhtml
SQL 準備 :mysql
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) ;
1. id 相同時執行順序從上至下。算法
2. id 不一樣時 , 若是是子查詢 ,id 的序號會遞增, 序號越大的越先執行。sql
3. id 相同,不一樣都存在時,id 相同的能夠認爲是一組查詢按從上至下的順序執行。id 值越大越優先執行。緩存
4. id 爲 NULL , 若是行引用其餘行的聯合結果,則值能夠爲NULL。在這種狀況下,表列顯示像<unionM,N>這樣的值,以指示該行引用id值爲M和N的行的並。服務器
1. SIMPLE :簡單的查詢沒有使用 UNION 或者是子查詢 。oop
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 語句,依賴外層查詢。spa
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 語句 , 沒法緩存結果的子查詢。
關聯優化器會爲查詢選擇關聯順序,左側深度優先當 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 的行。
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能在優化階段分解查詢語句,在執行階段甚至用不到訪問表或索引(高效)。
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操做,在找到第一匹配的元組後即中止找一樣值的動做。