若想查看MySQL優化器優化後的sql語句可使用以下語句:html
EXPLAIN EXTENDED sql_statement; -- show warnings緊接着上面的語句執行 SHOW WARNINGS\G;
Explain輸出字段:mysql
Column | 含義 |
---|---|
id | 查詢序號 |
select_type | 查詢類型 |
table | 表名 |
partitions | 匹配的分區 |
type | join類型 |
prossible_keys | 可能會選擇的索引 |
key | 實際選擇的索引 |
key_len | 索引的長度 |
ref | 與索引做比較的列 |
rows | 要檢索的行數(估算值) |
filtered | 查詢條件過濾的行數的百分比 |
Extra | 額外信息 |
select的標識符。整個查詢語句中每一個select的序列號。id越大的SELECT最早被執行,對於id相同的記錄,順序由上往下。若此行引用的是其餘行UNION的結果,則id值爲NULL。算法
查詢類型,包含如下幾種: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緩存
輸出行所引用的表。也能夠爲以下的值:session
此查詢匹配到的分區。只有在PARTITIONS關鍵字被使用的時候此字段會顯示。若表沒有分區則值爲NULL。函數
聯接類型,下面詳細介紹各類join類型,順序爲從最優類型到最差類型:oop
表中只有一行數據(= system table)。這是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;
多表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可用於使用'='或'<=>'操做符做比較的索引列。在下面的例子中,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;
在用到全文索引時會使用此類型。
除了MySQL會額外查詢包含NULL值的行,此類型跟ref同樣。此類型經常使用在解析子查詢的時候。在以下的例子中,MySQL使用ref_or_null類型:
SELECT * FROM ref_table WHERE key_column=expr OR key_column IS NULL;
表示使用了索引合併優化。在這種狀況下,key列包含了使用的索引的列表,key_len列包含了使用的索引的最長部分的列表。更多信息:Index Merge Optimization
對於以下形式的IN子查詢,使用此類型替換eq_ref類型:
value IN (SELECT primary_key FROM single_table WHERE some_expr)
unique_subquery 僅是一個索引查找功能,可以以更高的效率徹底替換子查詢。
跟unique_subquery相似。能夠替代IN子查詢,可是它適用於以下形式子查詢中的非惟一索引:
value IN (SELECT key_column FROM single_table WHERE some_expr)
使用索引查詢記錄,只取回指定範圍的行。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);
除了掃描的是索引樹,此類型跟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。
指出MySQL可使用哪些索引從表中查詢記錄。這些索引沒有優先級之分。
若是該列爲NULL,則沒有相應的索引。在這種狀況下,須要檢查WHERE條件引用的字段是否加上了合適的索引。若是沒有創建合適的索引,建立適當的索引並使用explain來評估此查詢。
能夠經過 SHOW INDEX FROM table_name
查看錶中的索引。
MySQL實際使用的索引。key的取值也可能不在prossible_keys中。
經過在語句中使用 FORCE INDEX, USE INDEX, or IGNORE INDEX 來強制MySQL使用或忽略一個索引。詳情查看:Index Hints
被選中的索引的長度(單位:Byte)。若key列爲NULL,則key列值爲NULL。注意:經過key_len的值能夠肯定實際使用了聯合索引的哪些部分。
關於key_len值的計算,能夠查看此文章:http://imysql.com/2015/10/20/mysql-faq-key-len-in-explain.shtml
使用哪些列或常量跟key的值做比較來查詢記錄。若值爲func,那麼此值使用的是函數的結果。在EXPLAIN EXTENDED 語句以後使用 SHOW WARNINGS 能夠查看使用的是哪一個函數。
執行查詢時須要檢查的行數。對於InnoDB表,這是一個估算值,結果可能並不許確。
查詢條件過濾了表中多少行記錄,是一個估算的百分比值。rows列顯示的是行數的估算值,rows × filtered / 100 表示跟前面表做join的行數。此列只有在使用EXPLAIN EXTENDED時纔會展現。
解析查詢語句時的額外信息,以下:
MySQL須要額外的排序操做,以按順序返回數據。詳情查看: ORDER BY Optimization
只需從索引樹中返回所需字段的信息,而不須要額外從磁盤讀取實際數據。當查詢僅需返回單個索引中部分字段時,Extra字段顯示此信息。
跟 Using index 訪問方式相似,MySQL能夠從索引中取回GROUP BY或DISTINCT查詢所需的數據,而不須要額外從磁盤讀取實際數據。詳情查看: GROUP BY Optimization
使用了Index Condition Pushdown優化,詳情查看: Index Condition Pushdown Optimization
將join前面的表的一部分放到join buffer中,而後用buffer中的記錄跟當前表執行join操做。(Block Nested Loop) 表示使用Block Nested-Loop算法,(Batched Key Access) 表示使用Batched Key Access算法。就是說,前面的key列中出現的字段會放到join buffer中,而後從出現 Using join buffer 的那一行table字段列出的表中分批取回匹配的行。
使用了Multi-Range Read優化策略,詳情查看: Multi-Range Read Optimization
對於type值爲index_merge類型的聯接,使用了哪一種索引合併算法。關於索引合併優化能夠查看: Index Merge Optimization
爲了處理查詢,須要建立臨時表保存結果。若是查詢語句包含GROUP BY和ORDER BY而且列出的字段不同,Extra會出現此信息。
WHERE子句用於限制返回給客戶端或與下一個表匹配的記錄。除非你確實想要獲取或檢查表的全部行,不然查詢會有問題若Extra不包含Using where而且聯接類型爲ALL或index。
SHOW PROFILE
和 SHOW 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 n
後 SHOW 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)
參考: