MySQL Explain詳解

MySQL Explain詳解

若想查看MySQL優化器優化後的sql語句可使用以下語句:html

EXPLAIN EXTENDED sql_statement;
-- show warnings緊接着上面的語句執行
SHOW WARNINGS\G;

Explain輸出字段解釋

Explain輸出字段:mysql

Column 含義
id 查詢序號
select_type 查詢類型
table 表名
partitions 匹配的分區
type join類型
prossible_keys 可能會選擇的索引
key 實際選擇的索引
key_len 索引的長度
ref 與索引做比較的列
rows 要檢索的行數(估算值)
filtered 查詢條件過濾的行數的百分比
Extra 額外信息

id

select的標識符。整個查詢語句中每一個select的序列號。id越大的SELECT最早被執行,對於id相同的記錄,順序由上往下。若此行引用的是其餘行UNION的結果,則id值爲NULL。算法

select_type

查詢類型,包含如下幾種:sql

select_type 類型說明
SIMPLE 簡單SELECT(不使用UNION或子查詢)
PRIMARY 最外層的SELECT
UNION UNION中第二個或以後的SELECT語句
DEPENDENT UNION UNION中第二個或以後的SELECT語句取決於外面的查詢
UNION RESULT UNION的結果
SUBQUERY 子查詢中的第一個SELECT
DEPENDENT SUBQUERY 子查詢中的第一個SELECT, 取決於外面的查詢
DERIVED 衍生表(FROM子句中的子查詢)
MATERIALIZED 物化子查詢
UNCACHEABLE SUBQUERY 結果集沒法緩存的子查詢,必須從新評估外部查詢的每一行
UNCACHEABLE UNION UNION中第二個或以後的SELECT,屬於沒法緩存的子查詢

DEPENDENT 意味着使用了關聯子查詢。關於關聯子查詢查看:Correlated Subqueries緩存

table

輸出行所引用的表。也能夠爲以下的值:session

  • <unionM,N>: 引用id爲M和N UNION後的結果。
  • <derivedN>: 引用id爲N的結果派生出的表。派生表能夠是一個結果集,例如派生自FROM中子查詢的結果。
  • <subqueryN>: 引用id爲N的子查詢結果物化獲得的表。即生成一個臨時表保存子查詢的結果。詳情查看: Optimizing Subqueries with Subquery Materialization

partitions

此查詢匹配到的分區。只有在PARTITIONS關鍵字被使用的時候此字段會顯示。若表沒有分區則值爲NULL。函數

type

聯接類型,下面詳細介紹各類join類型,順序爲從最優類型到最差類型:oop

system

表中只有一行數據(= system table)。這是const類型的一個特例。性能

const

最多隻有一行記錄匹配,它將在查詢開始時被讀取。因爲僅有一行記錄匹配,因此此條記錄的列值可被優化器視爲常數。由於只讀取一次,因此const表很快。優化

聯合主鍵或惟一索引的全部字段跟常量值比較時,join類型爲const。在下面的查詢中,tlb_name能夠被用做const表:

SELECT * FROM tbl_name WHERE primary_key=1;
SELECT * FROM tbl_name WHERE unique_key=1;
SELECT * FROM tbl_name
  WHERE primary_key_part1=1 AND primary_key_part2=2;

eq_ref

多表join時,對於來自前面表的每一行,在當前表中只能找到一行。這多是除了system和const以外最好的類型。當主鍵或惟一非NULL索引的全部字段都被用做join聯接時會使用此類型。

eq_ref可用於使用'='操做符做比較的索引列。比較的值能夠是常量,也能夠是使用在此表以前讀取的表的列的表達式。在下面的例子中,MySQL可以使用eq_ref類型來處理ref_table:

SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column=other_table.column;

SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column_part1=other_table.column
  AND ref_table.key_column_part2=1;

ref

對於來自前面表的每一行,在此表的索引中能夠匹配到多行。若聯接只用到索引的最左前綴或索引不是主鍵或惟一索引時,使用ref類型(也就是說,此聯接可以匹配多行記錄)。

ref可用於使用'='或'<=>'操做符做比較的索引列。在下面的例子中,MySQL使用ref類型來處理ref_table:

SELECT * FROM ref_table WHERE key_column=expr;

SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column=other_table.column;

SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column_part1=other_table.column
  AND ref_table.key_column_part2=1;

fulltext

在用到全文索引時會使用此類型。

ref_or_null

除了MySQL會額外查詢包含NULL值的行,此類型跟ref同樣。此類型經常使用在解析子查詢的時候。在以下的例子中,MySQL使用ref_or_null類型:

SELECT * FROM ref_table
  WHERE key_column=expr OR key_column IS NULL;

index_merge

表示使用了索引合併優化。在這種狀況下,key列包含了使用的索引的列表,key_len列包含了使用的索引的最長部分的列表。更多信息:Index Merge Optimization

unique_subquery

對於以下形式的IN子查詢,使用此類型替換eq_ref類型:

value IN (SELECT primary_key FROM single_table WHERE some_expr)

unique_subquery 僅是一個索引查找功能,可以以更高的效率徹底替換子查詢。

index_subquery

跟unique_subquery相似。能夠替代IN子查詢,可是它適用於以下形式子查詢中的非惟一索引:

value IN (SELECT key_column FROM single_table WHERE some_expr)

range

使用索引查詢記錄,只取回指定範圍的行。key列顯示使用了哪一個索引,key_len列包含了使用了此索引的長度。此類型下的ref列值爲NULL。

當索引列使用=, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN()操做符與常量做比較時,會用到range類型。

SELECT * FROM tbl_name WHERE key_column = 10;

SELECT * FROM tbl_name WHERE key_column BETWEEN 10 and 20;

SELECT * FROM tbl_name WHERE key_column IN (10,20,30);

SELECT * FROM tbl_name
  WHERE key_part1 = 10 AND key_part2 IN (10,20,30);

index

除了掃描的是索引樹,此類型跟ALL類型相同。

若此索引對於查詢來講爲覆蓋索引,而且僅經過掃描索引樹就能獲得查詢所需的數據。這種狀況下,Extra列會顯示_Using index_。僅掃描索引樹比ALL類型更快的緣由:索引數據一般比表的數據小。

當只查詢索引中的部分字段時,MySQL可使用此聯接類型。

CREATE TABLE `store_location` (
  `store_id` int(11) NOT NULL DEFAULT '0',
  `store_name` varchar(30) DEFAULT NULL,
  `province_id` int(11) DEFAULT NULL,
  `city_id` int(11) DEFAULT NULL,
  `district_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`store_id`),
  KEY `idx_location` (`province_id`,`city_id`,`district_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

insert into store_location values(1,'adidas',110,230,560);
insert into store_location values(2,'nike',111,231,561);
insert into store_location values(3,'new banlace',112,232,562);
insert into store_location values(4,'puma',113,233,563);

mysql> explain select province_id,city_id,district_id from store_location where city_id > 231;
+----+-------------+----------------+-------+---------------+--------------+---------+------+------+--------------------------+
| id | select_type | table          | type  | possible_keys | key          | key_len | ref  | rows | Extra                    |
+----+-------------+----------------+-------+---------------+--------------+---------+------+------+--------------------------+
|  1 | SIMPLE      | store_location | index | NULL          | idx_location | 15      | NULL |    4 | Using where; Using index |
+----+-------------+----------------+-------+---------------+--------------+---------+------+------+--------------------------+
1 row in set (0.00 sec)

ALL

即全表掃面,性能最差。能夠經過適當添加索引來避免出現ALL。

prossible_keys

指出MySQL可使用哪些索引從表中查詢記錄。這些索引沒有優先級之分。

若是該列爲NULL,則沒有相應的索引。在這種狀況下,須要檢查WHERE條件引用的字段是否加上了合適的索引。若是沒有創建合適的索引,建立適當的索引並使用explain來評估此查詢。

能夠經過 SHOW INDEX FROM table_name 查看錶中的索引。

key

MySQL實際使用的索引。key的取值也可能不在prossible_keys中。

經過在語句中使用 FORCE INDEX, USE INDEX, or IGNORE INDEX 來強制MySQL使用或忽略一個索引。詳情查看:Index Hints

key_len

被選中的索引的長度(單位:Byte)。若key列爲NULL,則key列值爲NULL。注意:經過key_len的值能夠肯定實際使用了聯合索引的哪些部分。

關於key_len值的計算,能夠查看此文章:http://imysql.com/2015/10/20/mysql-faq-key-len-in-explain.shtml

ref

使用哪些列或常量跟key的值做比較來查詢記錄。若值爲func,那麼此值使用的是函數的結果。在EXPLAIN EXTENDED 語句以後使用 SHOW WARNINGS 能夠查看使用的是哪一個函數。

rows

執行查詢時須要檢查的行數。對於InnoDB表,這是一個估算值,結果可能並不許確。

filtered

查詢條件過濾了表中多少行記錄,是一個估算的百分比值。rows列顯示的是行數的估算值,rows × filtered / 100 表示跟前面表做join的行數。此列只有在使用EXPLAIN EXTENDED時纔會展現。

Extra

解析查詢語句時的額外信息,以下:

Using filesort

MySQL須要額外的排序操做,以按順序返回數據。詳情查看: ORDER BY Optimization

Using index

只需從索引樹中返回所需字段的信息,而不須要額外從磁盤讀取實際數據。當查詢僅需返回單個索引中部分字段時,Extra字段顯示此信息。

Using index for group-by

跟 Using index 訪問方式相似,MySQL能夠從索引中取回GROUP BY或DISTINCT查詢所需的數據,而不須要額外從磁盤讀取實際數據。詳情查看: GROUP BY Optimization

Using index condition

使用了Index Condition Pushdown優化,詳情查看: Index Condition Pushdown Optimization

Using join buffer (Block Nested Loop), Using join buffer (Batched Key Access)

將join前面的表的一部分放到join buffer中,而後用buffer中的記錄跟當前表執行join操做。(Block Nested Loop) 表示使用Block Nested-Loop算法,(Batched Key Access) 表示使用Batched Key Access算法。就是說,前面的key列中出現的字段會放到join buffer中,而後從出現 Using join buffer 的那一行table字段列出的表中分批取回匹配的行。

Using MRR

使用了Multi-Range Read優化策略,詳情查看: Multi-Range Read Optimization

Using sort_union(...), Using union(...), Using intersect(...)

對於type值爲index_merge類型的聯接,使用了哪一種索引合併算法。關於索引合併優化能夠查看: Index Merge Optimization

Using temporary

爲了處理查詢,須要建立臨時表保存結果。若是查詢語句包含GROUP BY和ORDER BY而且列出的字段不同,Extra會出現此信息。

Using where

WHERE子句用於限制返回給客戶端或與下一個表匹配的記錄。除非你確實想要獲取或檢查表的全部行,不然查詢會有問題若Extra不包含Using where而且聯接類型爲ALL或index。

Profiling的使用

SHOW PROFILESHOW PROFILES 能夠查看在當前session中查詢語句的資源使用狀況的分析信息。 SHOW PROFILE句法格式:

SHOW PROFILE [type [, type] ... ]
    [FOR QUERY n]
    [LIMIT row_count [OFFSET offset]]

type:
    ALL
  | BLOCK IO
  | CONTEXT SWITCHES
  | CPU
  | IPC
  | MEMORY
  | PAGE FAULTS
  | SOURCE
  | SWAPS

Profiling功能能夠經過session變量來控制,默認值爲0(OFF)。能夠經過以下語句設置爲開啓狀態:

mysql> SET profiling = 1;

SHOW PROFILES 語句能夠查看當前session中最近執行的語句的一個列表。此列表的大小經過session變量 profiling_history_size 設置,默認值爲15,最大值爲100。將此變量設置爲0至關於禁用Profiling。

SHOW PROFILE 語句能夠查看一條sql語句的詳細信息。若不包含 FOR QUERY n 子句,輸出的是最近一條語句的信息。加上 FOR QUERY nSHOW PROFILE 顯示語句n的信息。

更多關於profiling的信息,查看MySQL官網:SHOW PROFILE Syntax

以下代碼爲使用profiling的例子:

mysql> SET profiling = 1;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test_c where b = 1;
+---+------+
| a | b    |
+---+------+
| 1 |    1 |
+---+------+
1 row in set (0.02 sec)

mysql> select * from test_d where b = 1;
+---+------+------+------+
| a | b    | c    | d    |
+---+------+------+------+
| 1 |    1 |    1 | 111  |
| 5 |    1 |    1 | 511  |
+---+------+------+------+
2 rows in set (0.03 sec)

mysql> show profiles;
+----------+------------+----------------------------------+
| Query_ID | Duration   | Query                            |
+----------+------------+----------------------------------+
|        1 | 0.01119375 | select * from test_c where b = 1 |
|        2 | 0.02607875 | select * from test_d where b = 1 |
+----------+------------+----------------------------------+

mysql> show profile for query 2;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000121 |
| checking permissions | 0.000033 |
| Opening tables       | 0.000041 |
| init                 | 0.000048 |
| System lock          | 0.000035 |
| optimizing           | 0.000039 |
| statistics           | 0.014997 |
| preparing            | 0.000046 |
| executing            | 0.000024 |
| Sending data         | 0.010304 |
| end                  | 0.000042 |
| query end            | 0.000025 |
| closing tables       | 0.000028 |
| freeing items        | 0.000059 |
| cleaning up          | 0.000239 |
+----------------------+----------+
15 rows in set, 1 warning (0.01 sec)

mysql> show profile cpu,block io for query 8;
+----------------------+----------+----------+------------+--------------+---------------+
| Status               | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |
+----------------------+----------+----------+------------+--------------+---------------+
| starting             | 0.000121 | 0.000000 |   0.000000 |            0 |             0 |
| checking permissions | 0.000033 | 0.000000 |   0.000000 |            0 |             0 |
| Opening tables       | 0.000041 | 0.000000 |   0.000000 |            0 |             0 |
| init                 | 0.000048 | 0.000000 |   0.000000 |            0 |             0 |
| System lock          | 0.000035 | 0.000000 |   0.000000 |            0 |             0 |
| optimizing           | 0.000039 | 0.000000 |   0.000000 |            0 |             0 |
| statistics           | 0.014997 | 0.000999 |   0.000000 |          128 |             0 |
| preparing            | 0.000046 | 0.000000 |   0.000000 |            0 |             0 |
| executing            | 0.000024 | 0.000000 |   0.000000 |            0 |             0 |
| Sending data         | 0.010304 | 0.000000 |   0.000000 |            0 |             0 |
| end                  | 0.000042 | 0.000000 |   0.000000 |            0 |             0 |
| query end            | 0.000025 | 0.000000 |   0.000000 |            0 |             0 |
| closing tables       | 0.000028 | 0.000000 |   0.000000 |            0 |             0 |
| freeing items        | 0.000059 | 0.000000 |   0.000000 |            0 |             0 |
| cleaning up          | 0.000239 | 0.000000 |   0.000000 |            0 |             0 |
+----------------------+----------+----------+------------+--------------+---------------+
15 rows in set, 1 warning (0.00 sec)

-- 最後關閉profiling
mysql> set profiling = 0;
Query OK, 0 rows affected, 1 warning (0.01 sec)

參考:

相關文章
相關標籤/搜索