做者:Mr林_月生
來源:https://www.jianshu.com/p/8cc...html
mysql中的explain命令能夠用來查看sql語句是否使用了索引,用了什麼索引,有沒有作全表掃描。能夠幫助咱們優化查詢語句。mysql
explain出來的信息有10列,文章主要介紹type、key、Extra這幾個字段。git
演示中涉及到的表結構以下:github
CREATE TABLE `dept_desc` ( `dept_no` char(4) NOT NULL, `dept_name` varchar(40) NOT NULL, `desc` varchar(255) NOT NULL, PRIMARY KEY (`dept_no`) ) ENGINE=InnoDB CREATE TABLE `dept_emp` ( `emp_no` int(11) NOT NULL, `dept_no` char(4) NOT NULL, `from_date` date NOT NULL, `to_date` date NOT NULL, PRIMARY KEY (`emp_no`,`dept_no`), KEY `dept_no` (`dept_no`), CONSTRAINT `dept_emp_ibfk_1` FOREIGN KEY (`emp_no`) REFERENCES `employees` (`emp_no`) ON DELETE CASCADE, CONSTRAINT `dept_emp_ibfk_2` FOREIGN KEY (`dept_no`) REFERENCES `departments` (`dept_no`) ON DELETE CASCADE ) ENGINE=InnoDB CREATE TABLE `employees` ( `emp_no` int(11) NOT NULL, `birth_date` date NOT NULL, `first_name` varchar(14) NOT NULL, `last_name` varchar(16) NOT NULL, `gender` enum('M','F') NOT NULL, `hire_date` date NOT NULL, PRIMARY KEY (`emp_no`) ) ENGINE=InnoDB
上面的表都是mysql中測試庫的表,須要的同窗能夠自行去下載。
官方文檔: https://dev.mysql.com/doc/emp...;
github下載地址: https://github.com/datacharme..._db.git
sql語句實際執行時使用的索引列,有時候mysql可能會選擇優化效果不是最好的索引,這時,咱們能夠在select語句中使用force index(INDEXNAME)來強制mysql使用指定索引或使用ignore index(INDEXNAME)強制mysql忽略指定索引算法
訪問類型,表示數據庫引擎查找表的方式,常見的type類型有:sql
all,index,range,ref,eq_ref,const。數據庫
全表掃描,表示sql語句會把表中全部表數據所有讀取讀取掃描一遍。效率最低,咱們應儘可能避免。segmentfault
mysql> explain select * from dept_emp; +----+-------------+----------+------+---------------+------+---------+------+--------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+----------+------+---------------+------+---------+------+--------+-------+ | 1 | SIMPLE | dept_emp | ALL | NULL | NULL | NULL | NULL | 331570 | NULL | +----+-------------+----------+------+---------------+------+---------+------+--------+-------+
全索引掃描,表示sql語句將會把整顆二級索引樹所有讀取掃描一遍,由於二級索引併發
樹的數據量比全表數據量小,因此效率比all高一些。通常查詢語句中查詢字段爲索性能
引字段,且無where子句時,type會爲index。以下,mysql肯定使用dept_no這
個索引,而後掃描整個dept_no索引樹獲得結果。
mysql> explain select dept_no from dept_emp; +----+-------------+----------+-------+---------------+---------+---------+------+--------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+----------+-------+---------------+---------+---------+------+--------+-------------+ | 1 | SIMPLE | dept_emp | index | NULL | dept_no | 4 | NULL | 331570 | Using index | +----+-------------+----------+-------+---------------+---------+---------+------+--------+-------------+
部分索引掃描,當查詢爲區間查詢,且查詢字段爲索引字段時,這時會根據where條件對索引進行部分掃描。
mysql> explain select * from dept_emp where emp_no > '7'; +----+-------------+----------+-------+---------------+---------+---------+------+--------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+----------+-------+---------------+---------+---------+------+--------+-------------+ | 1 | SIMPLE | dept_emp | range | PRIMARY | PRIMARY | 4 | NULL | 165785 | Using where | +----+-------------+----------+-------+---------------+---------+---------+------+--------+-------------+
出現於where操做符爲‘=’,且where字段爲非惟一索引的單表查詢或聯表查詢。
// 單表 mysql> explain select * from dept_emp where dept_no = 'd005'; +----+-------------+----------+------+---------------+---------+---------+-------+--------+-----------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+----------+------+---------------+---------+---------+-------+--------+-----------------------+ | 1 | SIMPLE | dept_emp | ref | dept_no | dept_no | 4 | const | 145708 | Using index condition | +----+-------------+----------+------+---------------+---------+---------+-------+--------+-----------------------+ // 聯表 mysql> explain select * from dept_emp,departments where dept_emp.dept_no = departments.dept_no; +----+-------------+-------------+-------+---------------+-----------+---------+-------------------------------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+-------+---------------+-----------+---------+-------------------------------+------+-------------+ | 1 | SIMPLE | departments | index | PRIMARY | dept_name | 42 | NULL | 9 | Using index | | 1 | SIMPLE | dept_emp | ref | dept_no | dept_no | 4 | employees.departments.dept_no | 1 | NULL | +----+-------------+-------------+-------+---------------+-----------+---------+-------------------------------+------+-------------+
出現於where操做符爲‘=’,且where字段爲惟一索引的聯表查詢。
mysql> explain select * from departments,dept_desc where departments.dept_name=dept_desc.dept_name; +----+-------------+-------------+--------+---------------+-----------+---------+-------------------------------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+--------+---------------+-----------+---------+-------------------------------+------+-------------+ | 1 | SIMPLE | dept_desc | ALL | NULL | NULL | NULL | NULL | 1 | NULL | | 1 | SIMPLE | departments | eq_ref | dept_name | dept_name | 42 | employees.dept_desc.dept_name | 1 | Using index | +----+-------------+-------------+--------+---------------+-----------+---------+-------------------------------+------+-------------+
出現於where操做符爲‘=’,且where字段爲惟一索引的單表查詢,此時最多隻會匹配到一行。
mysql> explain select * from departments where dept_no = 'd005'; +----+-------------+-------------+-------+---------------+---------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+-------+---------------+---------+---------+-------+------+-------+ | 1 | SIMPLE | departments | const | PRIMARY | PRIMARY | 4 | const | 1 | NULL | +----+-------------+-------------+-------+---------------+---------+---------+-------+------+-------+
綜上,單從type字段考慮效率,const > eq_ref > ref > range > index > all.
注意:咱們不能僅僅根據type去判斷兩條sql的執行速度。例如type爲range的查詢不必定比type爲index的全表查詢速度要快,還要看具體的sql。由於type爲index時,查詢是不須要回表操做的,而type爲range時,有可能須要回表操做。如sqlA("select dept_no from dept_emp;")和sqlB("select from_date from dept_emp where dept_no > 'd005';"),這個時候sqlB根據where條件掃描索引樹後,須要回表查詢相應的行數據,以獲取from_date的值,而sqlA雖然掃描了整顆索引樹,但並不須要回表,因此速度可能會比sqlB更快。
extra列會包含一些十分重要的信息,咱們能夠根據這些信息進行sql優化
using index: sql語句沒有where查詢條件,使用覆蓋索引,不須要回表查詢便可拿到結果
using where: 沒有使用索引/使用了索引但須要回表查詢且沒有使用到下推索引
using index && useing where: sql語句有where查詢條件,且使用覆蓋索引,不須要回表查詢便可拿到結果。
Using index condition:使用索引查詢,sql語句的where子句查詢條件字段均爲同一索引字段,且開啓索引下推功能,須要回表查詢便可拿到結果。
Using index condition && using where:使用索引查詢,sql語句的where子句查詢條件字段存在非同一索引字段,且開啓索引下推功能,須要回表查詢便可拿到結果。
using filesort: 當語句中存在order by時,且orderby字段不是索引,這個時候mysql沒法利用索引進行排序,只能用排序算法從新進行排序,會額外消耗資源。
Using temporary:創建了臨時表來保存中間結果,查詢完成以後又要把臨時表刪除。會很影響性能,需儘快優化。
有時在extra字段中會出現"Impossible WHERE noticed after reading const tables"這種描述。翻看網上資料後,我的發現這是mysql一種很怪的處理方式。
當sql語句知足:
一、根據主鍵查詢或者惟一性索引查詢;
二、where操做符爲"="時。
在sql語句優化階段,mysql會先根據查詢條件找到相關記錄,這樣,若是這條數據不存在,實際上就進行了一次全掃描,而後得出一個結論,該數據不在表中。這樣對於併發較高的數據庫,會加大負載。因此,若是數據不用惟一的話,普通的索引比惟一索引更好用。
若有錯誤或其它問題,歡迎小夥伴留言評論、指正。若有幫助,歡迎點贊+轉發分享。
歡迎你們關注民工哥的公衆號:民工哥技術之路