EXPLAIN 關鍵字能夠用於獲取 SQL 語句執行計劃的相關信息,在 MySQL 8.0 中,EXPLAIN 支持大多數 SQL 語句,如 SELECT 、DELETE 、INSERT 、REPLACE、和 UPDATE 。示例以下:html
mysql> EXPLAIN SELECT * FROM employees;
+----+-------------+-----------+------+---------------+------+---------+------+--------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+------+---------+------+--------+-------+
| 1 | SIMPLE | employees | ALL | NULL | NULL | NULL | NULL | 299379 | NULL |
+----+-------------+-----------+------+---------------+------+---------+------+--------+-------+
複製代碼
注:本篇文章的測試數據來源於 MySQL 官方提供的 Employees Sample Database,其數據庫結構以下:mysql
如下分別介紹 EXPLAIN 輸出結果中各個字段的含義:git
id 爲行標識符,同時也表示語句執行的優先級,值越大則優先級越高。特殊狀況下,若是某行語句引用了其餘多行結果集的並集,則該值能夠爲 NULL。示例以下:github
# 該FROM字句只是用於演示,並無任何實際意義
mysql> EXPLAIN SELECT COUNT(1) FROM (SELECT emp_no FROM salaries) AS t;
+----+-------------+------------+-------+---------------+---------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+---------+---------+------+---------+-------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 2757635 | NULL |
| 2 | DERIVED | salaries | index | NULL | PRIMARY | 7 | NULL | 2757635 | Using index |
+----+-------------+------------+-------+---------------+---------+---------+------+---------+-------------+
複製代碼
# 查詢工資大於500000或部門編號等於d007的全部僱員的編號
mysql> EXPLAIN SELECT emp_no FROM salaries WHERE salary>500000 UNION ALL SELECT emp_no FROM dept_emp WHERE dept_no = "d007";
+----+--------------+------------+------+---------------+---------+---------+-------+---------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+------------+------+---------------+---------+---------+-------+---------+--------------------------+
| 1 | PRIMARY | salaries | ALL | NULL | NULL | NULL | NULL | 2837161 | Using where |
| 2 | UNION | dept_emp | ref | dept_no | dept_no | 4 | const | 91566 | Using where; Using index |
| NULL | UNION RESULT | <union1,2> | ALL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------+------------+------+---------------+---------+---------+-------+---------+--------------------------+
複製代碼
select_type 用於表示查詢的類型,常見類型及其含義以下:sql
這裏以查詢類型爲 SUBQUERY 的狀況進行演示,示例以下:shell
# 根據員工編號查詢員工姓名及其工資總和
mysql> EXPLAIN SELECT first_name,(SELECT sum(salary) FROM salaries WHERE emp_no = 10001) FROM employees WHERE emp_no = 10001;
+----+-------------+-----------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+---------+---------+-------+------+-------+
| 1 | PRIMARY | employees | const | PRIMARY | PRIMARY | 4 | const | 1 | NULL |
| 2 | SUBQUERY | salaries | ref | PRIMARY | PRIMARY | 4 | const | 17 | NULL |
+----+-------------+-----------+-------+---------------+---------+---------+-------+------+-------+
複製代碼
表示語句執行的目標表,除了正常的表名或表別名外,還會出現如下取值:數據庫
type 字段是進行性能判斷的重要依據,它表示 MySQL 使用何種方式來查找目標數據集,不一樣查找方式會致使不一樣的性能開銷,常見查找方式及其性能表現按照由高到低的順序排序以下:bash
1. system:這是 const 類型的一個特例,只會出如今待查詢的表只有一行數據的狀況下。服務器
2. const:常出如今主鍵或惟一索引與常量值進行比較的場景下,此時查詢性能是最優的。性能
mysql> EXPLAIN SELECT * FROM employees WHERE emp_no = 10008;
+----+-------------+-----------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+---------+---------+-------+------+-------+
| 1 | SIMPLE | employees | const | PRIMARY | PRIMARY | 4 | const | 1 | NULL |
+----+-------------+-----------+-------+---------------+---------+---------+-------+------+-------+
複製代碼
3. eq_ref:當鏈接使用的是完整的索引而且是 PRIMARY KEY 或 UNIQUE NOT NULL INDEX 時使用它。
# 這裏員工部門關係表 dept_no 的聯合主鍵爲 emp_no + dept_no ,即員工編號+部門標號
mysql> EXPLAIN SELECT * FROM employees e,dept_emp d WHERE e.emp_no = d.emp_no AND dept_no = "d005";
+----+-------------+-------+--------+-----------------+---------+---------+--------------------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-----------------+---------+---------+--------------------+------+-----------------------+
| 1 | SIMPLE | d | ref | PRIMARY,dept_no | dept_no | 4 | const | 1 | Using index condition |
| 1 | SIMPLE | e | eq_ref | PRIMARY | PRIMARY | 4 | employees.d.emp_no | 1 | NULL |
+----+-------------+-------+--------+-----------------+---------+---------+--------------------+------+-----------------------+
複製代碼
4. ref:當鏈接使用的是前綴索引或鏈接條件不是 PRIMARY KEY 或 UNIQUE INDEX 時則使用它。
# 這裏僅使用了前綴索引emp_no,因此其類型爲 ref , 而不是 eq_ref
mysql> EXPLAIN SELECT * FROM employees e,dept_emp d WHERE e.emp_no = d.emp_no;
+----+-------------+-------+------+---------------+---------+---------+--------------------+--------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+---------+---------+--------------------+--------+-------+
| 1 | SIMPLE | e | ALL | PRIMARY | NULL | NULL | NULL | 299379 | NULL |
| 1 | SIMPLE | d | ref | PRIMARY | PRIMARY | 4 | employees.e.emp_no | 1 | NULL |
+----+-------------+-------+------+---------------+---------+---------+--------------------+--------+-------+
複製代碼
5. ref_or_null:相似於 ref 類型的查詢,可是附加了對 NULL 值列的查詢。示例語句以下:
SELECT * FROM ref_table WHERE key_column=expr OR key_column IS NULL;
複製代碼
6. index_merge:該聯接類型表示使用了索引進行合併優化,示例以下:
mysql> EXPLAIN SELECT * FROM dept_emp WHERE dept_no = "d004" AND emp_no < 10020;
+----+-------------+----------+-------------+-----------------+-----------------+---------+------+------+-----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+-------------+-----------------+-----------------+---------+------+------+-----------------------------------------------+
| 1 | SIMPLE | dept_emp | index_merge | PRIMARY,dept_no | dept_no,PRIMARY | 8,4 | NULL | 1 | Using intersect(dept_no,PRIMARY); Using where |
+----+-------------+----------+-------------+-----------------+-----------------+---------+------+------+-----------------------------------------------+
複製代碼
7. range:使用索引進行範圍掃描,常見於 between、> 、< 這樣的查詢條件。
mysql> EXPLAIN SELECT * FROM employees WHERE emp_no > 10000;
+----+-------------+-----------+-------+---------------+---------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+---------+---------+------+--------+-------------+
| 1 | SIMPLE | employees | range | PRIMARY | PRIMARY | 4 | NULL | 149689 | Using where |
+----+-------------+-----------+-------+---------------+---------+---------+------+--------+-------------+
複製代碼
8. index:索引鏈接類型與 ALL 相同,只是掃描的是索引樹,一般出如今索引是該查詢的覆蓋索引的狀況:
mysql> EXPLAIN SELECT emp_no FROM employees;
+----+-------------+-----------+-------+---------------+---------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+---------+---------+------+--------+-------------+
| 1 | SIMPLE | employees | index | NULL | PRIMARY | 4 | NULL | 299379 | Using index |
+----+-------------+-----------+-------+---------------+---------+---------+------+--------+-------------+
複製代碼
9. ALL:全表掃描,效率最差的查找方式。
mysql> EXPLAIN SELECT * FROM employees WHERE first_name ="Bezalel";
+----+-------------+-----------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | employees | ALL | NULL | NULL | NULL | NULL | 299379 | Using where |
+----+-------------+-----------+------+---------------+------+---------+------+--------+-------------+
複製代碼
表示在執行過程當中可能會用到哪些索引來進行優化。
表示在執行過程當中實際用到的用於優化的索引。
表示使用到的索引的字節數。
顯示哪些列或常量與 key 列中指定的索引進行比較。
MySQL 爲了找到目標行而讀取的全部行的數量,這是一個估算的值。
Extra 列主要用於顯示額外的信息,常見信息及其含義以下:
1. Using where :MySQL 服務器會在存儲引擎檢索行後再進行過濾。示例以下:
# first_name 字段是一個普通的列,非索引列
mysql> EXPLAIN SELECT * FROM employees WHERE first_name = "Sumant";
+----+-------------+-----------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | employees | ALL | NULL | NULL | NULL | NULL | 299379 | Using where |
+----+-------------+-----------+------+---------------+------+---------+------+--------+-------------+
複製代碼
2. Using filesort:一般出如今 GROUP BY 或 ORDER BY 語句中,且排序或分組沒有基於索引,此時須要使用文件在內存中進行排序。由於使用索引排序的性能好於使用文件排序,因此出現這種狀況能夠考慮經過添加索引進行優化。示例以下:
mysql> EXPLAIN SELECT * FROM employees ORDER BY first_name ;
+----+-------------+-----------+------+---------------+------+---------+------+--------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+------+---------+------+--------+----------------+
| 1 | SIMPLE | employees | ALL | NULL | NULL | NULL | NULL | 299379 | Using filesort |
+----+-------------+-----------+------+---------------+------+---------+------+--------+----------------+
複製代碼
3. Using index:使用了覆蓋索引進行查詢,此時不須要訪問表,從索引中就能夠獲取到所需的所有數據。示例以下:
mysql> EXPLAIN SELECT emp_no FROM employees;
+----+-------------+-----------+-------+---------------+---------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+---------+---------+------+--------+-------------+
| 1 | SIMPLE | employees | index | NULL | PRIMARY | 4 | NULL | 299379 | Using index |
+----+-------------+-----------+-------+---------------+---------+---------+------+--------+-------------+
複製代碼
4. Using temporary:表示須要使用臨時表來處理查詢,常出如今 GROUP BY 或 ORDER BY 語句中,示例以下:
mysql> EXPLAIN SELECT first_name,count(first_name) FROM employees GROUP BY first_name ;
+----+-------------+-----------+------+---------------+------+---------+------+--------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+------+---------+------+--------+---------------------------------+
| 1 | SIMPLE | employees | ALL | NULL | NULL | NULL | NULL | 299379 | Using temporary; Using filesort |
+----+-------------+-----------+------+---------------+------+---------+------+--------+---------------------------------+
複製代碼
更多參數的說明能夠參考 MySQL 官方文檔:dev.mysql.com/doc/refman/…
更多文章,歡迎訪問 [全棧工程師手冊] ,GitHub 地址:github.com/heibaiying/…