MYSQL EXPLAIN執行計劃命令詳解(支持更新中)

本文來自個人github pages博客http://galengao.github.io/ 即www.gaohuirong.cnhtml

摘要:node

  • 本篇是根據官網中的每一個一點來翻譯、舉例、驗證的;英語很差,因此有些話語未必準確,請自行查看官網,如有些點下面沒有例子的是由於當時一會兒沒有想出那麼多來,若是你們有趕上好的例子,歡迎在下面留言我持續更新
  • 查看執行計劃的關鍵EXPLAIN
  • 版本MYSQL5.6,用到的庫是官網例子sakila,自行下載導入

因爲要把每一個點都翻譯出來,還須要舉例,因此須要必定的時間,本人先把架構理出來,而後逐個點開始mysql

官網地址:http://dev.mysql.com/doc/refman/5.6/en/explain-output.htmlgit

EXPLAIN語句返回MYSLQ的執行計劃,經過他返回的信息,咱們能瞭解到MYSQL優化器是如何執行SQL語句的,經過分析他能幫助你提供優化的思路。github

語法

MYSQL 5.6.3之前只能EXPLAIN SELECT; MYSQL5.6.3之後就能夠EXPLAIN SELECT,UPDATE,DELETEsql

  • EXPLAIN 語法例子:
mysql> explain select customer_id,a.store_id,first_name,last_name, b.manager_staff_id from customer a left join store b on a.store_id=b.store_id; +----+-------------+-------+--------+---------------+---------+---------+-------------------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+--------+---------------+---------+---------+-------------------+------+-------+ | 1 | SIMPLE | a | ALL | NULL | NULL | NULL | NULL | 599 | NULL | | 1 | SIMPLE | b | eq_ref | PRIMARY | PRIMARY | 1 | sakila.a.store_id | 1 | NULL | +----+-------------+-------+--------+---------------+---------+---------+-------------------+------+-------+ 2 rows in set
  • EXPLAIN還有一種語法,相似於desc
mysql> explain actor; +-------------+----------------------+------+-----+-------------------+-----------------------------+ | Field | Type | Null | Key | Default | Extra | +-------------+----------------------+------+-----+-------------------+-----------------------------+ | actor_id | smallint(5) unsigned | NO | PRI | NULL | auto_increment | | first_name | varchar(45) | NO | | NULL | | | last_name | varchar(45) | NO | MUL | NULL | | | last_update | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP | +-------------+----------------------+------+-----+-------------------+-----------------------------+ 4 rows in set

EXPLAIN的輸出

EXPLAIN主要包含如下信息:json

Column JSON Name Meaning
id select_id The SELECT identifier
select_type None The SELECT type
table table_name The table for the output row
partitions partitions The matching partitions
type access_type The join type
possible_keys possible_keys The possible indexes to choose
key key The index actually chosen
key_len key_length The length of the chosen key
ref ref The columns compared to the index
rows rows Estimate of rows to be examined
filtered filtered Percentage of rows filtered by table condition
Extra None Additional information

id (JSON name: select_id)

SQL查詢中的序列號。緩存

select_type (JSON name: none)

查詢的類型,能夠是下表的任何一種類型:ruby

select_type Value JSON Name Meaning
SIMPLE None 簡單查詢(不適用union和子查詢的)
PRIMARY None 最外層的查詢
UNION None UNION中的第二個或者後面的SELECT語句
DEPENDENT UNION dependent (true) UNION中的第二個或者後面的SELECT語句,依賴於外部查詢
UNION RESULT union_result UNION結果
SUBQUERY None 子查詢中的第一個SELECT語句
DEPENDENT SUBQUERY dependent (true) 子查詢中的第一個SELECT語句,依賴於外部查詢
DERIVED None 派生表的SELECT(FROM子句的子查詢)
MATERIALIZED materialized_from_subquery 物化子查詢
UNCACHEABLE SUBQUERY cacheable (false) 對於該結果不能被緩存,必須從新評估外部查詢的每一行子查詢
UNCACHEABLE UNION cacheable (false) UNION中的第二個或者後面的SELECT語句屬於不可緩存子查詢 (see UNCACHEABLE SUBQUERY)

查詢類型例子:架構

一、SIMPLE 簡單查詢(不適用union和子查詢的)

mysql> explain select * from staff; +----+-------------+-------+------+---------------+------+---------+------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-------+ | 1 | SIMPLE | staff | ALL | NULL | NULL | NULL | NULL | 2 | NULL | +----+-------------+-------+------+---------------+------+---------+------+------+-------+ 1 row in set

二、PRIMARY 最外層的查詢

mysql> explain select * from (select last_name,first_name from customer) a; +----+-------------+------------+------+---------------+------+---------+------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+------+---------------+------+---------+------+------+-------+ | 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 599 | NULL | | 2 | DERIVED | customer | ALL | NULL | NULL | NULL | NULL | 599 | NULL | +----+-------------+------------+------+---------------+------+---------+------+------+-------+ 2 rows in set

三、UNION UNION中的第二個或者後面的SELECT語句

mysql> explain select first_name,last_name from customer a where customer_id=1 union select first_name,last_name from customer b where customer_id=2; +------+--------------+------------+-------+---------------+---------+---------+-------+------+-----------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+--------------+------------+-------+---------------+---------+---------+-------+------+-----------------+ | 1 | PRIMARY | a | const | PRIMARY | PRIMARY | 2 | const | 1 | NULL | | 2 | UNION | b | const | PRIMARY | PRIMARY | 2 | const | 1 | NULL | | NULL | UNION RESULT | <union1,2> | ALL | NULL | NULL | NULL | NULL | NULL | Using temporary | +------+--------------+------------+-------+---------------+---------+---------+-------+------+-----------------+ 3 rows in set

四、DEPENDENT UNION UNION中的第二個或者後面的SELECT語句,依賴於外部查詢

mysql> explain select * from customer where customer_id in(select customer_id from customer a where customer_id=1 union all select customer_id from customer b where customer_id=2); +------+--------------------+------------+-------+---------------+---------+---------+-------+------+-----------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+--------------------+------------+-------+---------------+---------+---------+-------+------+-----------------+ | 1 | PRIMARY | customer | ALL | NULL | NULL | NULL | NULL | 599 | Using where | | 2 | DEPENDENT SUBQUERY | a | const | PRIMARY | PRIMARY | 2 | const | 1 | Using index | | 3 | DEPENDENT UNION | b | const | PRIMARY | PRIMARY | 2 | const | 1 | Using index | | NULL | UNION RESULT | <union2,3> | ALL | NULL | NULL | NULL | NULL | NULL | Using temporary | +------+--------------------+------------+-------+---------------+---------+---------+-------+------+-----------------+ 4 rows in set

五、UNION RESULT UNION結果

mysql> explain select * from staff union select * from staff; +------+--------------+------------+------+---------------+------+---------+------+------+-----------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+--------------+------------+------+---------------+------+---------+------+------+-----------------+ | 1 | PRIMARY | staff | ALL | NULL | NULL | NULL | NULL | 2 | NULL | | 2 | UNION | staff | ALL | NULL | NULL | NULL | NULL | 2 | NULL | | NULL | UNION RESULT | <union1,2> | ALL | NULL | NULL | NULL | NULL | NULL | Using temporary | +------+--------------+------------+------+---------------+------+---------+------+------+-----------------+ 3 rows in set

六、SUBQUERY 子查詢中的第一個SELECT語句

mysql> explain select customer_id from customer where store_id = (select store_id from store where store_id=1); +----+-------------+----------+-------+-----------------+-----------------+---------+-------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+----------+-------+-----------------+-----------------+---------+-------+------+--------------------------+ | 1 | PRIMARY | customer | ref | idx_fk_store_id | idx_fk_store_id | 1 | const | 326 | Using where; Using index | | 2 | SUBQUERY | store | const | PRIMARY | PRIMARY | 1 | const | 1 | Using index | +----+-------------+----------+-------+-----------------+-----------------+---------+-------+------+--------------------------+ 2 rows in set

有興趣的能夠去把=號換成in試試

七、DERIVED 派生表的SELECT(FROM子句的子查詢)

mysql> explain select * from (select * from customer) a; +----+-------------+------------+------+---------------+------+---------+------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+------+---------------+------+---------+------+------+-------+ | 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 599 | NULL | | 2 | DERIVED | customer | ALL | NULL | NULL | NULL | NULL | 599 | NULL | +----+-------------+------------+------+---------------+------+---------+------+------+-------+ 2 rows in set

八、其它如物化視圖等查詢本身去造例子去

table(JSON name: table_name)

顯示這一行的數據是關於哪張表的,也能夠是下列值之一:
unionM,N: The row refers to the union of the rows with id values of M and N.
derivedN: The row refers to the derived table result for the row with an id value of N. A derived table may result, for example, from a subquery in the FROM clause.
subqueryN: The row refers to the result of a materialized subquery for the row with an id value of N.

partitions (JSON name: partitions)

分區中的記錄將被查詢相匹配。顯示此列僅在使用分區關鍵字。該值爲NULL對於非分區表。

type (JSON name: access_type)

EXPLAIN輸出的類型列描述了表的鏈接方法。下面的列表介紹了鏈接類型,從最好的類型到最差的命令:

一、system 
這是const的一個特例聯接類型。表只有一行(=系統表)。

mysql> explain select * from (select * from customer where customer_id=1) a; +----+-------------+------------+--------+---------------+---------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+--------+---------------+---------+---------+-------+------+-------+ | 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 1 | NULL | | 2 | DERIVED | customer | const | PRIMARY | PRIMARY | 2 | const | 1 | NULL | +----+-------------+------------+--------+---------------+---------+---------+-------+------+-------+ 2 rows in set

二、const

表最多有一個匹配行,它將在查詢開始時被讀取。由於僅有一行,在這行的列值可被優化器剩餘部分認爲是常數。const表很快,由於它們只讀取一次! 
const用於用常數值比較PRIMARY KEY或UNIQUE索引的全部部分時。在下面的查詢中,tbl_name能夠用於const表:

SELECT * from tbl_name WHERE primary_key=1SELECT * from tbl_name WHERE primary_key_part1=1primary_key_part2=2

三、eq_ref

對於每一個來自於前面的表的行組合,從該表中讀取一行。這多是最好的聯接類型,除了const類型。它用在一個索引的全部部分被聯接使用而且索引是UNIQUE或PRIMARY KEY。 
eq_ref能夠用於使用= 操做符比較的帶索引的列。比較值能夠爲常量或一個使用在該表前面所讀取的表的列的表達式。
在下面的例子中,MySQL可使用eq_ref聯接來處理ref_tables:

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使用的是非惟一索引或者普通索引。id是主鍵 mysql> explain select a.*,b.* from testa a,testb b where a.id=b.id ; +----+-------------+-------+--------+---------------+---------+---------+-------------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+--------+---------------+---------+---------+-------------+------+-------------+ | 1 | SIMPLE | b | ALL | NULL | NULL | NULL | NULL | 1 | Using where | | 1 | SIMPLE | a | eq_ref | PRIMARY | PRIMARY | 4 | sakila.b.id | 1 | NULL | +----+-------------+-------+--------+---------------+---------+---------+-------------+------+-------------+ 2 rows in set

四、ref

對於每一個來自於前面的表的行組合,全部有匹配索引值的行將從這張表中讀取。若是聯接只使用鍵的最左邊的前綴,或若是鍵不是UNIQUE或PRIMARY KEY(換句話說,若是聯接不能基於關鍵字選擇單個行的話),則使用ref。若是使用的鍵僅僅匹配少許行,該聯接類型是不錯的。 
ref能夠用於使用=或<=>操做符的帶索引的列。 
在下面的例子中,MySQL可使用ref聯接來處理ref_tables:

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;
# 使用非惟一性索引或者惟一索引的前綴掃描,返回匹配某個單獨值的記錄行。name有非惟一性索引 mysql> explain select * from testa where name='aaa'; +----+-------------+-------+------+---------------+----------+---------+-------+------+-----------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+----------+---------+-------+------+-----------------------+ | 1 | SIMPLE | testa | ref | idx_name | idx_name | 33 | const | 2 | Using index condition | +----+-------------+-------+------+---------------+----------+---------+-------+------+-----------------------+ 1 row in set mysql> explain select a.*,b.* from testa a,testb b where a.name=b.cname; +----+-------------+-------+------+---------------+----------+---------+----------------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+----------+---------+----------------+------+-------------+ | 1 | SIMPLE | b | ALL | NULL | NULL | NULL | NULL | 1 | Using where | | 1 | SIMPLE | a | ref | idx_name | idx_name | 33 | sakila.b.cname | 1 | NULL | +----+-------------+-------+------+---------------+----------+---------+----------------+------+-------------+ 2 rows in set

五、 fulltext

使用FULLTEXT索引進行聯接。

六、ref_or_null

該聯接類型如同ref,可是添加了MySQL能夠專門搜索包含NULL值的行。在解決子查詢中常用該聯接類型的優化。
在下面的例子中,MySQL可使用ref_or_null聯接來處理ref_tables:

SELECT * FROM ref_table WHERE key_column=expr OR key_column IS NULL;
mysql> explain select * from (select cusno from testa t1,testb t2 where t1.id=t2.id) t where cusno =2 or cusno is null; +----+-------------+------------+-------------+---------------+-------------+---------+--------------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+-------------+---------------+-------------+---------+--------------+------+--------------------------+ | 1 | PRIMARY | <derived2> | ref_or_null | <auto_key0> | <auto_key0> | 5 | const | 2 | Using where; Using index | | 2 | DERIVED | t2 | index | PRIMARY | PRIMARY | 4 | NULL | 1 | Using index | | 2 | DERIVED | t1 | eq_ref | PRIMARY | PRIMARY | 4 | sakila.t2.id | 1 | NULL | +----+-------------+------------+-------------+---------------+-------------+---------+--------------+------+--------------------------+ 3 rows in set

此處按照官網的格式未測試出例子來,如有例子的請留言,我測試更新

七、index_merge

該聯接類型表示使用了索引合併優化方法。在這種狀況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。

此處按照官網的格式未測試出例子來,如有例子的請留言,我測試更新

八、unique_subquery

unique_subquery是一個索引查找函數,能夠徹底替換子查詢,效率更高。
該類型替換了下面形式的IN子查詢的ref:

value IN (SELECT primary_key FROM single_table WHERE some_expr)

此處按照官網的格式未測試出例子來,如有例子的請留言,我測試更新

九、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掃描的要快,由於索引樹比表數據小不少。

全表掃描被用到從索引中去讀取數據, Extra列就不會顯示用Using index

若是查詢僅僅是索引列,那MySQL會這個index索引類型

mysql> alter table testa add primary key p_id(id); Query OK, 0 rows affected Records: 0 Duplicates: 0 Warnings: 0 mysql> create index idx_name on testa(name); Query OK, 0 rows affected Records: 0 Duplicates: 0 Warnings: 0 mysql> insert into testa values(2,2,'aaa'); Query OK, 1 row affected # 由於查詢的列name上建有索引,因此若是這樣type走的是index mysql> explain select name from testa; +----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+ | 1 | SIMPLE | testa | index | NULL | idx_name | 33 | NULL | 2 | Using index | +----+-------------+-------+-------+---------------+----------+---------+------+------+-------------+ 1 row in set # 由於查詢的列cusno沒有建索引,或者查詢的列包含沒有索引的列,這樣查詢就會走ALL掃描,以下: mysql> explain select cusno from testa; +----+-------------+-------+------+---------------+------+---------+------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-------+ | 1 | SIMPLE | testa | ALL | NULL | NULL | NULL | NULL | 2 | NULL | +----+-------------+-------+------+---------------+------+---------+------+------+-------+ 1 row in set # *包含有未見索引的列 mysql> explain select * from testa; +----+-------------+-------+------+---------------+------+---------+------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-------+ | 1 | SIMPLE | testa | ALL | NULL | NULL | NULL | NULL | 2 | NULL | +----+-------------+-------+------+---------------+------+---------+------+------+-------+ 1 row in set

十二、all

對於每一個來自於先前的表的行組合,進行完整的表掃描。若是表是第一個沒標記const的表,這一般很差,而且一般在它狀況下不好。一般能夠增長更多的索引而不要使用ALL,使得行能基於前面的表中的常數值或列值被檢索出。

possible_keys (JSON name: possible_keys)

possible_keys列指出MySQL能使用哪一個索引在該表中找到行。而下面的key是MYSQL實際用到的索引,這意味着在possible_keys中的是計劃中的,而key是實際的,也就是計劃中有這個索引,實際執行時未必能用到。

若是該列是NULL,則沒有相關的索引。在這種狀況下,能夠經過檢查WHERE子句看是否它引用某些列或適合索引的列來提升你的查詢性能。若是是這樣,創造一個適當的索引而且再次用EXPLAIN檢查查詢。

例子參考下面

key (JSON name: key)

key列顯示MySQL實際決定使用的鍵(索引)。

若是沒有選擇索引,鍵是NULL。要想強制MySQL使用或忽視possible_keys列中的索引,在查詢中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。

例子參考下面

key_len (JSON name: key_length)

key_len列顯示MySQL決定使用的鍵長度。若是KEY鍵是NULL,則長度爲NULL。
使用的索引的長度。在不損失精確性的狀況下,長度越短越好.

例子參考下面

ref (JSON name: ref)

ref列顯示使用哪一個列或常數與key一塊兒從表中選擇行。 它顯示的是列的名字(或單詞「const」),MySQL將根據這些列來選擇行。

例子參考下面

rows (JSON name: rows)

rows列顯示MySQL認爲它執行查詢時必須檢查的行數。

例子參考下面

filtered (JSON name: filtered)

若是你用EXPLAIN EXTENDED將會展現出這列filtered(MySQL5.7缺省就會輸出filtered),它指返回結果的行佔須要讀到的行(rows列的值)的百分比。按說filtered是個很是有用的值,由於對於join操做,前一個表的結果集大小直接影響了循環的次數。可是個人環境下測試的結果倒是,filtered的值一直是100%,也就是說失去了意義。

上面部分EXPLAIN展現的列的例子:

mysql> alter table testa add primary key p_id(id); Query OK, 0 rows affected Records: 0 Duplicates: 0 Warnings: 0 mysql> create index idx_name on testa(name); Query OK, 0 rows affected Records: 0 Duplicates: 0 Warnings: 0 mysql> insert into testa values(2,2,'aaa'); Query OK, 1 row affected # 下面possible_keys可能會用到的索引有主鍵和我建的索引,可是key實際用到的是主鍵,主鍵長度是4,ref用的列的名字(或單詞「const」,此處用的是常量const,速度快,rows掃描的只有1行 mysql> explain select cusno from testa where id=2 and name='aaa'; +----+-------------+-------+-------+------------------+---------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+------------------+---------+---------+-------+------+-------+ | 1 | SIMPLE | testa | const | PRIMARY,idx_name | PRIMARY | 4 | const | 1 | NULL | +----+-------------+-------+-------+------------------+---------+---------+-------+------+-------+ 1 row in set # 下面雖然name有索引,可是查詢的列cusno沒有索引,這時mysql計劃possible_keys有索引,但實際key未走索引,若果cusno換成有索引的列,參照下面。 mysql> explain select cusno from testa where name='aaa'; +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | testa | ALL | idx_name | NULL | NULL | NULL | 1 | Using where | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ 1 row in set # id是有主鍵索引的,這時實際key已經走索引了,若果查詢列換成既有索引的列也有無索引的列,參照下面 mysql> explain select id from testa where name='aaa'; +----+-------------+-------+------+---------------+----------+---------+-------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+----------+---------+-------+------+--------------------------+ | 1 | SIMPLE | testa | ref | idx_name | idx_name | 33 | const | 2 | Using where; Using index | +----+-------------+-------+------+---------------+----------+---------+-------+------+--------------------------+ 1 row in set # 證實只要你查詢的列包含有無索引列就不走索引 mysql> explain select cusno,name from testa where name='aaa'; +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | testa | ALL | idx_name | NULL | NULL | NULL | 1 | Using where | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ 1 row in set

Extra (JSON name: none)

該列包含MySQL解決查詢的詳細信息,下面詳細.

一、Child of ‘table’ pushed join@1 (JSON: message text)

This table is referenced as the child of table in a join that can be pushed down to the NDB kernel. Applies only in MySQL Cluster, when pushed-down joins are enabled. See the description of the ndb_join_pushdown server system variable for more information and examples.

二、const row not found (JSON property: const_row_not_found)

For a query such as SELECT … FROM tbl_name, the table was empty.

三、Deleting all rows (JSON property: message)

For DELETE, some storage engines (such as MyISAM) support a handler method that removes all table rows in a simple and fast way. This Extra value is displayed if the engine uses this optimization.

四、Distinct (JSON property: distinct)

MySQL is looking for distinct values, so it stops searching for more rows for the current row combination after it has found the first matching row.

五、FirstMatch(tbl_name) (JSON property: first_match)

The semi-join FirstMatch join shortcutting strategy is used for tbl_name.

六、Full scan on NULL key (JSON property: message)

This occurs for subquery optimization as a fallback strategy when the optimizer cannot use an index-lookup access method.

七、Impossible HAVING (JSON property: message)

The HAVING clause is always false and cannot select any rows.

八、Impossible WHERE (JSON property: message)

The WHERE clause is always false and cannot select any rows.

九、Impossible WHERE noticed after reading const tables (JSON property: message)

MySQL has read all const (and system) tables and notice that the WHERE clause is always false.

十、LooseScan(m..n) (JSON property: message)

The semi-join LooseScan strategy is used. m and n are key part numbers.

十一、Materialize, Scan (JSON: message text)

Before MySQL 5.6.7, this indicates use of a single materialized temporary table. If Scan is present, no temporary table index is used for table reads. Otherwise, an index lookup is used. See also the Start materialize entry.

As of MySQL 5.6.7, materialization is indicated by rows with a select_type value of MATERIALIZED and rows with a table value of .

十二、No matching min/max row (JSON property: message)

No row satisfies the condition for a query such as SELECT MIN(…) FROM … WHERE condition.

1三、no matching row in const table (JSON property: message)

For a query with a join, there was an empty table or a table with no rows satisfying a unique index condition.

1四、No matching rows after partition pruning (JSON property: message)

For DELETE or UPDATE, the optimizer found nothing to delete or update after partition pruning. It is similar in meaning to Impossible WHERE for SELECT statements.

1五、No tables used (JSON property: message)

The query has no FROM clause, or has a FROM DUAL clause.

For INSERT or REPLACE statements, EXPLAIN displays this value when there is no SELECT part. For example, it appears for EXPLAIN INSERT INTO t VALUES(10) because that is equivalent to EXPLAIN INSERT INTO t SELECT 10 FROM DUAL.

1六、Not exists (JSON property: message)

MySQL was able to do a LEFT JOIN optimization on the query and does not examine more rows in this table for the previous row combination after it finds one row that matches the LEFT JOIN criteria. Here is an example of the type of query that can be optimized this way:

SELECT * FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;

Assume that t2.id is defined as NOT NULL. In this case, MySQL scans t1 and looks up the rows in t2 using the values of t1.id. If MySQL finds a matching row in t2, it knows that t2.id can never be NULL, and does not scan through the rest of the rows in t2 that have the same id value. In other words, for each row in t1, MySQL needs to do only a single lookup in t2, regardless of how many rows actually match in t2.

1七、Range checked for each record (index map: N) (JSON property: message)

MySQL found no good index to use, but found that some of indexes might be used after column values from preceding tables are known. For each row combination in the preceding tables, MySQL checks whether it is possible to use a range or index_merge access method to retrieve rows. This is not very fast, but is faster than performing a join with no index at all. The applicability criteria are as described in Section 8.2.1.3, 「Range Optimization」, and Section 8.2.1.4, 「Index Merge Optimization」, with the exception that all column values for the preceding table are known and considered to be constants.

Indexes are numbered beginning with 1, in the same order as shown by SHOW INDEX for the table. The index map value N is a bitmask value that indicates which indexes are candidates. For example, a value of 0x19 (binary 11001) means that indexes 1, 4, and 5 will be considered.

1八、Scanned N databases (JSON property: message)

This indicates how many directory scans the server performs when processing a query for INFORMATION_SCHEMA tables, as described in Section 8.2.4, 「Optimizing INFORMATION_SCHEMA Queries」. The value of N can be 0, 1, or all.

1九、Select tables optimized away (JSON property: message)

The optimizer determined 1) that at most one row should be returned, and 2) that to produce this row, a deterministic set of rows must be read. When the rows to be read can be read during the optimization phase (for example, by reading index rows), there is no need to read any tables during query execution.

The first condition is fulfilled when the query is implicitly grouped (contains an aggregate function but no GROUP BY clause). The second condition is fulfilled when one row lookup is performed per index used. The number of indexes read determines the number of rows to read.

Consider the following implicitly grouped query:

SELECT MIN(c1), MIN(c2) FROM t1;

Suppose that MIN(c1) can be retrieved by reading one index row and MIN(c2) can be retrieved by reading one row from a different index. That is, for each column c1 and c2, there exists an index where the column is the first column of the index. In this case, one row is returned, produced by reading two deterministic rows.

This Extra value does not occur if the rows to read are not deterministic. Consider this query:

SELECT MIN(c2) FROM t1 WHERE c1 <= 10;

Suppose that (c1, c2) is a covering index. Using this index, all rows with c1 <= 10 must be scanned to find the minimum c2 value. By contrast, consider this query:

SELECT MIN(c2) FROM t1 WHERE c1 = 10;

In this case, the first index row with c1 = 10 contains the minimum c2 value. Only one row must be read to produce the returned row.

For storage engines that maintain an exact row count per table (such as MyISAM, but not InnoDB), this Extra value can occur for COUNT(*) queries for which the WHERE clause is missing or always true and there is no GROUP BY clause. (This is an instance of an implicitly grouped query where the storage engine influences whether a deterministic number of rows can be read.)

20、Skip_open_table, Open_frm_only, Open_trigger_only, Open_full_table (JSON property: message)

These values indicate file-opening optimizations that apply to queries for INFORMATION_SCHEMA tables, as described in Section 8.2.4, 「Optimizing INFORMATION_SCHEMA Queries」.

Skip_open_table: Table files do not need to be opened. The information has already become available within the query by scanning the database directory.

Open_frm_only: Only the table’s .frm file need be opened.

Open_trigger_only: Only the table’s .TRG file need be opened.

Open_full_table: The unoptimized information lookup. The .frm, .MYD, and .MYI files must be opened.

2一、Start materialize, End materialize, Scan (JSON: message text)

Before MySQL 5.6.7, this indicates use of multiple materialized temporary tables. If Scan is present, no temporary table index is used for table reads. Otherwise, an index lookup is used. See also the Materialize entry.

As of MySQL 5.6.7, materialization is indicated by rows with a select_type value of MATERIALIZED and rows with a table value of .

2二、Start temporary, End temporary (JSON property: message)

This indicates temporary table use for the semi-join Duplicate Weedout strategy.

2三、unique row not found (JSON property: message)

For a query such as SELECT … FROM tbl_name, no rows satisfy the condition for a UNIQUE index or PRIMARY KEY on the table.

2四、Using filesort (JSON property: using_filesort)

MySQL must do an extra pass to find out how to retrieve the rows in sorted order. The sort is done by going through all rows according to the join type and storing the sort key and pointer to the row for all rows that match the WHERE clause. The keys then are sorted and the rows are retrieved in sorted order. See Section 8.2.1.15, 「ORDER BY Optimization」.

2五、Using index (JSON property: using_index)

The column information is retrieved from the table using only information in the index tree without having to do an additional seek to read the actual row. This strategy can be used when the query uses only columns that are part of a single index.

For InnoDB tables that have a user-defined clustered index, that index can be used even when Using index is absent from the Extra column. This is the case if type is index and key is PRIMARY.

2六、Using index condition (JSON property: using_index_condition)

Tables are read by accessing index tuples and testing them first to determine whether to read full table rows. In this way, index information is used to defer (「push down」) reading full table rows unless it is necessary. See Section 8.2.1.6, 「Index Condition Pushdown Optimization」.

2七、Using index for group-by (JSON property: using_index_for_group_by)

Similar to the Using index table access method, Using index for group-by indicates that MySQL found an index that can be used to retrieve all columns of a GROUP BY or DISTINCT query without any extra disk access to the actual table. Additionally, the index is used in the most efficient way so that for each group, only a few index entries are read. For details, see Section 8.2.1.16, 「GROUP BY Optimization」.

2八、Using join buffer (Block Nested Loop), Using join buffer (Batched Key Access) (JSON property: using_join_buffer)

Tables from earlier joins are read in portions into the join buffer, and then their rows are used from the buffer to perform the join with the current table. (Block Nested Loop) indicates use of the Block Nested-Loop algorithm and (Batched Key Access) indicates use of the Batched Key Access algorithm. That is, the keys from the table on the preceding line of the EXPLAIN output will be buffered, and the matching rows will be fetched in batches from the table represented by the line in which Using join buffer appears.

In JSON-formatted output, the value of using_join_buffer is always either one of Block Nested Loop or Batched Key Access.

2九、Using MRR (JSON property: message)

Tables are read using the Multi-Range Read optimization strategy. See Section 8.2.1.13, 「Multi-Range Read Optimization」.

30、Using sort_union(…), Using union(…), Using intersect(…) (JSON property: message)

These indicate how index scans are merged for the index_merge join type. See Section 8.2.1.4, 「Index Merge Optimization」.

3一、Using temporary (JSON property: using_temporary_table)

To resolve the query, MySQL needs to create a temporary table to hold the result. This typically happens if the query contains GROUP BY and ORDER BY clauses that list columns differently.

3二、Using where (JSON property: attached_condition)

A WHERE clause is used to restrict which rows to match against the next table or send to the client. Unless you specifically intend to fetch or examine all rows from the table, you may have something wrong in your query if the Extra value is not Using where and the table join type is ALL or index.

Using where has no direct counterpart in JSON-formatted output; the attached_condition property contains any WHERE condition used.

3三、Using where with pushed condition (JSON property: message)

This item applies to NDB tables only. It means that MySQL Cluster is using the Condition Pushdown optimization to improve the efficiency of a direct comparison between a nonindexed column and a constant. In such cases, the condition is 「pushed down」 to the cluster’s data nodes and is evaluated on all data nodes simultaneously. This eliminates the need to send nonmatching rows over the network, and can speed up such queries by a factor of 5 to 10 times over cases where Condition Pushdown could be but is not used. For more information, see Section 8.2.1.5, 「Engine Condition Pushdown Optimization」.

相關文章
相關標籤/搜索