介紹 本篇主要通過彙總網上的大牛的知識,簡單介紹一下如何使用mysql的執行計劃,並根據執行計劃判斷如何優化和是否索引最優。 執行計劃可顯示估計查詢語句執行計劃,從中可以分析查詢的執行情況是否最優,有助於對不使用索引的語句進行優化。EXPLAIN對每個查詢返回一行信息,列出了有序的表格,MySQL處 ...
介紹
本篇主要通過彙總網上的大牛的知識,簡單介紹一下如何使用mysql的執行計劃,並根據執行計劃判斷如何優化和是否索引最優。
執行計劃可顯示估計查詢語句執行計劃,從中可以分析查詢的執行情況是否最優,有助於對不使用索引的語句進行優化。EXPLAIN對每個查詢返回一行信息,列出了有序的表格,MySQL處理語句的時候讀取他們。MySQL解決所有的連接使用嵌套連接方法。這意味讀取第一張一行,然後匹配第二張表的所有行,第三張表甚至更多表。當所有的表在處理時,MySQL會輸出已經查詢出來的列,並且回溯到表繼續查找直到所有的行被找到,從該表讀取下一行,直到程式繼續處理下一張表。
使用關鍵詞 EXTENDED ,EXPLAIN 會處理通過 SHOW WARNINGS 看到的一些額外信息。EXPLAIN EXTENDED 會顯示這些濾出的列。
語法:
EXPLAIN <select statement>;
輸出表格欄位如下:
mysql> explain select * from mysql.user where user='root'; +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | user | ALL | NULL | NULL | NULL | NULL | 4 | Using where | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+
Column |
JSONName |
Meaning |
---|---|---|
|
|
查詢標識。id越大優先執行;id相同自上而下執行; |
|
None |
查詢的類型 |
|
|
查詢的表 |
|
|
Thematching partitions |
|
|
連接類型 |
|
|
可能選擇的索引 |
|
|
實際使用的索引 |
|
|
使用的索引長度 |
|
|
哪一列或常數在查詢中與索引鍵列一起使用 |
|
|
估計查詢的行數 |
|
|
被條件過濾掉的行數百分比 |
|
None |
解決查詢的一些額外信息 |
以下主要舉例說明3個欄位:select_type 、type、Extra
【select_type
】
alue |
JSONName |
Meaning |
---|---|---|
|
None |
|
|
None |
|
|
None |
|
|
|
|
|
|
|
|
None |
子查詢中第一個SELECT |
|
|
子查詢中第一個SELECT,獨立於外部查詢 |
|
None |
子查詢在 FROM子句中 |
|
|
物化子查詢(不清楚是什麼樣的查詢語句?) |
|
|
結果集不能被緩存的子查詢,必須重新評估外層查詢的每一行 |
|
|
|
創建測試表:
create table tabname ( id int auto_increment not null primary key, name varchar(10) null, indate datetime null, tid int null, key(tid), key(indate) )engine=innodb; create table tabname2 ( id int auto_increment not null primary key, name varchar(10) null, indate datetime null, tid int null, key(tid), key(indate) )engine=myisam; insert into tabname(name,indate,tid) values('love',now(),2),('lucky',now(),3),('passion',now(),4); insert into tabname2(name,indate,tid) values('love',now(),2),('lucky',now(),3),('passion',now(),4);
#SIMPLE
create table tabname ( id int auto_increment not null primary key, name varchar(10) null, indate datetime null, tid int null, key(tid), key(indate) )engine=innodb; create table tabname2 ( id int auto_increment not null primary key, name varchar(10) null, indate datetime null, tid int null, key(tid), key(indate) )engine=myisam; insert into tabname(name,indate,tid) values('love',now(),2),('lucky',now(),3),('passion',now(),4); insert into tabname2(name,indate,tid) values('love',now(),2),('lucky',now(),3),('passion',now(),4);
#PRIMARY / DERIVED
mysql> explain select * from (select * from tabname) as a; +----+-------------+------------+------+---------------+------+---------+------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+------+---------------+------+---------+------+------+-------+ | 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 3 | | | 2 | DERIVED | tabname | ALL | NULL | NULL | NULL | NULL | 3 | | +----+-------------+------------+------+---------------+------+---------+------+------+-------+
#PRIMARY / UNION / UNION RESULT
mysql> explain select * from tabname union select * from tabname; mysql> explain select * from tabname union all select * from tabname; +----+--------------+------------+------+---------------+------+---------+------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+--------------+------------+------+---------------+------+---------+------+------+-------+ | 1 | PRIMARY | tabname | ALL | NULL | NULL | NULL | NULL | 3 | | | 2 | UNION | tabname | ALL | NULL | NULL | NULL | NULL | 3 | | | NULL | UNION RESULT | <union1,2> | ALL | NULL | NULL | NULL | NULL | NULL | | +----+--------------+------------+------+---------------+------+---------+------+------+-------+
mysql> explain select * from tabname where id=(select max(id) from tabname); +----+-------------+---------+-------+---------------+---------+---------+-------+------+------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+---------+-------+---------------+---------+---------+-------+------+------------------------------+ | 1 | PRIMARY | tabname | const | PRIMARY | PRIMARY | 4 | const | 1 | | | 2 | SUBQUERY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away | +----+-------------+---------+-------+---------------+---------+---------+-------+------+------------------------------+
#PRIMARY / SUBQUERY
#PRIMARY / DEPENDENT SUBQUERY
[plain] view plain copymysql> explain select * from tabname a where exists(select 1 from tabname b where a.id=b.id); mysql> explain select *,(select name from tabname b where a.id=b.id) from tabname a; mysql> explain select * from tabname where id not in(select id from tabname); +----+--------------------+---------+-----------------+---------------+---------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+--------------------+---------+-----------------+---------------+---------+---------+------+------+-------------+ | 1 | PRIMARY | tabname | ALL | NULL | NULL | NULL | NULL | 3 | Using where | | 2 | DEPENDENT SUBQUERY | tabname | unique_subquery | PRIMARY | PRIMARY | 4 | func | 1 | Using index | +----+--------------------+---------+-----------------+---------------+---------+---------+------+------+-------------+
#PRIMARY / DEPENDENT UNION / DEPENDENT SUBQUERY / UNION RESULT
mysql> explain select * from tabname where id in (select id from tabname union select id from tabname); +----+--------------------+------------+--------+---------------+---------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+--------------------+------------+--------+---------------+---------+---------+------+------+-------------+ | 1 | PRIMARY | tabname | ALL | NULL | NULL | NULL | NULL | 3 | Using where | | 2 | DEPENDENT SUBQUERY | tabname | eq_ref | PRIMARY | PRIMARY | 4 | func | 1 | Using index | | 3 | DEPENDENT UNION | tabname | eq_ref | PRIMARY | PRIMARY | 4 | func | 1 | Using index | | NULL| UNION RESULT | <union2,3> | ALL | NULL | NULL | NULL | NULL | NULL | | +----+--------------------+------------+--------+---------------+---------+---------+------+------+-------------+
【type】
type |
Meaning |
---|---|
|
表僅一行數據 (=system table).這是const連接類型的特例。 |
|
|
|
|
|
對於前面表的結果集匹配查詢的所有行,當連接使用索引key時,或者索引不是 |
|
|
|
使用全文索引時出現。 |
|
使用了索引合併優化。(未成功) |
|
該類型將ref替換成以下子查詢的格式: valueIN (SELECTprimary_key FROMsingle_table WHERE some_expr) |
|
與 valueIN (SELECTkey_columnFROMsingle_table WHERE some_expr) |
|
使用索引檢索給定範圍內的行。 |
|
|
|
對於前面表的結果集中,進行了全表掃描。最差的一種類型,應考慮查詢優化了! |
查詢類型性能由優到差:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
#system
mysql> explain select id from(select id from tabname where id=1) as a; +----+-------------+------------+--------+---------------+---------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+--------+---------------+---------+---------+------+------+-------------+ | 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 1 | | | 2 | DERIVED | tabname | const | PRIMARY | PRIMARY | 4 | | 1 | Using index | +----+-------------+------------+--------+---------------+---------+---------+------+------+-------------+
#const
mysql> explain select * from tabname as a,tabname as b where a.id=b.id and a.id=1; mysql> explain select * from tabname where id=1; +----+-------------+---------+-------+---------------+---------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+---------+-------+---------------+---------+---------+-------+------+-------+ | 1 | SIMPLE | tabname | const | PRIMARY | PRIMARY | 4 | const | 1 | | +----+-------------+---------+-------+---------------+---------+---------+-------+------+-------+
#eq_ref(engine=myisam)
mysql> explain select * from tabname2 as a,tabname2 as b where a.id=b.id; +----+-------------+-------+--------+---------------+---------+---------+-----------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+--------+---------------+---------+---------+-----------+------+-------+ | 1 | SIMPLE | a | ALL | PRIMARY | NULL | NULL | NULL | 3 | | | 1 | SIMPLE | b | eq_ref | PRIMARY | PRIMARY | 4 | test.a.id | 1 | | +----+-------------+-------+--------+---------------+---------+---------+-----------+------+-------+
#ref
mysql> explain select * from tabname as a,tabname as b where a.tid=b.tid and a.tid=2; mysql> explain select * from tabname where tid=2; +----+-------------+---------+------+---------------+------+---------+-------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+---------+------+---------------+------+---------+-------+------+-------------+ | 1 | SIMPLE | tabname | ref | tid | tid | 5 | const | 1 | Using where | +----+-------------+---------+------+---------------+------+---------+-------+------+-------------+
#ref_or_null
mysql> explain select id,tid from tabname where tid=2 or tid is null; +----+-------------+---------+-------------+---------------+------+---------+-------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+---------+-------------+---------------+------+---------+-------+------+--------------------------+ | 1 | SIMPLE | tabname | ref_or_null | tid | tid | 5 | const | 2 | Using where; Using index | +----+-------------+---------+-------------+---------------+------+---------+-------+------+--------------------------+
#fulltext
mysql> explain select id,tid from tabname where tid=2 or tid is null; +----+-------------+---------+-------------+---------------+------+---------+-------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+---------+-------------+---------------+------+---------+-------+------+--------------------------+ | 1 | SIMPLE | tabname | ref_or_null | tid | tid | 5 | const | 2 | Using where; Using index | +----+-------------+---------+-------------+---------------+------+---------+-------+------+--------------------------+
#index_merge(未成功)
mysql> explain select * from tabname where tid>1 or indate<now(); mysql> explain select * from tabname where (tid>1 or indate>now()) AND name<'kk';
#unique_subquery
mysql> explain select * from tabname where tid in(select id from tabname); mysql> explain select * from tabname where id in(select id from tabname); +----+--------------------+---------+-----------------+---------------+---------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+--------------------+---------+-----------------+---------------+---------+---------+------+------+-------------+ | 1 | PRIMARY | tabname | ALL | NULL | NULL | NULL | NULL | 3 | Using where | | 2 | DEPENDENT SUBQUERY | tabname | unique_subquery | PRIMARY | PRIMARY | 4 | func | 1 | Using index | +----+--------------------+---------+-----------------+---------------+---------+---------+------+------+-------------+
#index_subquery
mysql> explain select * from tabname where tid in(select tid from tabname); mysql> explain select * from tabname where id in(select tid from tabname); +----+--------------------+---------+----------------+---------------+------+---------+------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+--------------------+---------+----------------+---------------+------+---------+------+------+--------------------------+ | 1 | PRIMARY | tabname | ALL | NULL | NULL | NULL | NULL | 3 | Using where | | 2 | DEPENDENT SUBQUERY | tabname | index_subquery | tid | tid | 5 | func | 1 | Using index; Using where | +----+--------------------+---------+----------------+---------------+------+---------+------+------+--------------------------+
#range
mysql> explain select * from tabname where tid between 1 and 2; mysql> explain