explain SELECT `pname`,`attrname`,`parts_unit`,`parts_price` FROM `wy_parts` LEFT JOIN wy_parts_attribute ON wy_parts_attribute.partsid = wy_parts.partsid WHERE wy_parts_attribute.paid = '15';
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
SQL執行的順序的標識,越大越先執行,如果說數字一樣大,那么就從上往下依次執行 | 查詢中每個select子句的類型 | 顯示這一行的數據是關於哪張表的,有時不是真實的表名字,看到的是derivedx(x是個數字,我的理解是第幾步執行的結果) | 顯示連接使用了何種類型。從最好到最差的連接類型為const(system)、eq_reg、ref、range、index和ALL(至少達到range級別最好能達到ref) | 顯示可能應用在這張表中的索引。如果為空,沒有可能的索引 | 實際使用的索引。如果為NULL,則沒有使用索引。很少的情況下,MYSQL會選擇優化不足的索引。這種情況下,可以在SELECT語句中使用USE INDEX(indexname)來強制使用一個possible_keys中的索引或者用IGNORE INDEX(indexname)來強制MYSQL忽略中的possible_keys索引 | 使用的索引的長度。在不損失精確性的情況下,長度越短越好 | 顯示索引的哪一列被使用了,如果可能的話,是一個常數;表示上述表的連接匹配條件,即哪些列或常量被用於查找索引列上的值 |
MYSQL認為必須檢查的用來返回請求數據的行數 | 關於MYSQL如何解析查詢的額外信息。壞的例子是Using temporary和Using filesort,意思MYSQL根本不能使用索引,結果是檢索會很慢 所以看到這兩個那就需要優化sql啦 |
總結:
EXPLAIN不會告訴你關於觸發器、存儲過程的信息或用戶自定義函數對查詢的影響情況
EXPLAIN不考慮各種Cache
EXPLAIN不能顯示MySQL在執行查詢時所作的優化工作
部分統計信息是估算的,並非精確值
EXPALIN只能解釋SELECT操作,其他操作要重寫為SELECT后查看執行計划。
id
說明:SQL執行的順序的標識,SQL從大到小的執行
1. id相同時,執行順序由上至下
2. 如果是子查詢,id的序號會遞增,id值越大優先級越高,越先被執行
3.id如果相同,可以認為是一組,從上往下順序執行;在所有組中,id值越大,優先級越高,越先執行
select_type
說明:查詢中每個select子句的類型
(1) SIMPLE: 簡單SELECT,不使用UNION或子查詢; 有連接查詢時,外層的查詢為simple,且只有一個
(2) PRIMARY: 一個需要union操作或者含有子查詢的select,位於最外層的單位查詢的select_type即為primary。且只有一個
(3) UNION : UNION中的第二個或后面的SELECT語句 union連接的兩個select查詢,第一個查詢是dervied派生表,除了第一個表外,第二個以后的表select_type都是union 若第二個SELECT出現在UNION之后,則被標記為UNION:若UNION包含在FROM子句的子查詢中,外層SELECT將被標記為:DERIVED (4)DEPENDENT UNION :與union一樣,出現在union 或union all語句中,但是這個查詢要受到外部查詢的影響
(5) UNION RESULT :包含union的結果集,在union和union all語句中,因為它不需要參與查詢,所以id字段為null
(6) SUBQUERY :除了from字句中包含的子查詢外,其他地方出現的子查詢都可能是subquery
(7) DEPENDENT SUBQUERY :子查詢中的第一個SELECT,取決於外面的查詢 與dependent union類似,表示這個subquery的查詢要受到外部表查詢的影響
(8) DERIVED :from字句中出現的子查詢,也叫做派生表,其他數據庫中可能叫做內聯視圖或嵌套select
(9) UNCACHEABLE SUBQUERY :一個子查詢的結果不能被緩存,必須重新評估外鏈接的第一行
table:
說明:顯示這一行的數據是關於哪張表的,如果查詢使用了別名,那么這里顯示的是別名 ,如果不涉及對數據表的操作,那么這顯示為null,如果顯示為尖括號括起來的<derived N>就表示這個是臨時表,后邊的N就是執行計划中的id,表示結果來自於這個查詢產生。如果是尖括號括起來的<union M,N>,與<derived N>類似,也是一個臨時表,表示這個結果來自於union查詢的id為M,N的結果集
說明:不同連接類型的解釋(按照效率由高->低的順序排序),除了all之外,其他的type都可以使用到索引,除了index_merge之外,其他的type只可以用到一個索引,一般來說,得保證查詢至少達到range級別,最好能達到ref
NULL: MySQL在優化過程中分解語句,執行時甚至不用訪問表或索引,例如從一個索引列里選取最小值可以通過單獨索引查找完成。
explain select 1 from dual where 1\G #dual是一個虛擬的表,可以直接忽略 select 1+1 from dual;
(system和const 應該是並列的)
system:表中只有一行數據或者是空表,且只能用於myisam和memory表。如果是Innodb引擎表,type列在這個情況通常都是all或者index
const:使用唯一索引或者主鍵,返回記錄一定是1行記錄的等值where條件時,通常type是const。其他數據庫也叫做唯一索引掃描(where primeryIdField=?或者uniqueIdField=?) 查找主鍵索引,返回的數據至多一條(0或者1條)。 屬於精確查找
explain select * from student where id = 1\G #注釋:如果上表中film表中只有一行數據,那么type就是system。
eq_ref:出現在要連接多個表的查詢計划中 類似ref,區別就在使用的索引是唯一索引,對於每個索引鍵值,表中只有一條記錄匹配,且這行數據是第二個表的主鍵或者唯一索引,且必須為not null,唯一索引和主鍵是多列時,只有所有的列都用作比較時才會出現eq_ref;簡單來說,就是多表連接中使用primary key或者 unique key作為關聯條件
查找唯一性索引,返回的數據至多一條。屬於精確查找
相對於ref來說就是使用的是唯一索引,對於每個索引鍵值,只有唯一的一條匹配記錄(在聯表查詢中使用primary key或者unique key作為關聯條件)
(在film和film_text中film_id都是主鍵,即都是唯一索引) mysql> explain select * from film a ,film_text b where a.film_id = b.film_id\G
mysql> ex[lain select * from student as s ,user as u where s.s_mobile=u.u_mobile;
ref:表示表的連接匹配條件,即哪些列或常量被用於查找索引列上的值 這個連接類型只有在查詢使用了不是惟一或主鍵的鍵或者是這些類型的部分(比如,利用最左邊前綴)時發生。對於之前的表的每一個行聯合,全部記錄都將從表中讀出。這個類型嚴重依賴於根據索引匹配的記錄多少—越少越好。(不像eq_ref那樣要求連接順序,也沒有主鍵和唯一索引的要求,只要使用相等條件檢索時就可能出現,常見與輔助索引的等值查找。或者多列主鍵、唯一索引中,使用第一個列之外的列作為等值查找也會出現,總之,返回數據不唯一的等值查找就可能出現。) 使用非唯一性索引或者唯一索引的前綴掃描,返回匹配某個單獨值的記錄行
查找非唯一性索引,返回匹配某一條件的多條數據。屬於精確查找、數據返回可能是多條
(1)使用非唯一性索引customer_id單表查詢 mysql> explain select * from payment where customer_id = 350; (2)使用非唯一性索引聯表查詢(由於customer_id在a表中不是主鍵,是普通索引(非唯一),所以是ref) mysql> explain select b.*, a.* from payment a ,customer b where a.customer_id = b.customer_id;
fulltext:全文索引檢索,要注意,全文索引的優先級很高,若全文索引和普通索引同時存在時,mysql不管代價,優先選擇使用全文索引
ref_or_null
index_merge:表示查詢使用了兩個以上的索引,最后取交集或者並集,常見and ,or的條件使用了不同的索引,官方排序這個在ref_or_null之后,但是實際上由於要讀取所個索引,性能可能大部分時間都不如range
range 索引范圍掃描,一個有限制的索引掃描。key 列顯示使用了哪個索引。當使用=、 <>、>、>=、<、<=、IS NULL、<=>、BETWEEN 或者 IN 操作符,用常量比較關鍵字列時,可以使用 range
只檢索給定范圍的行,索引范圍掃描,即查找某個索引的部分索引;常見於使用=,<>,>,<,>=,<=,<==>,is null,between ,in ,like等運算符的查詢中。
unique_subquery :
index_subquery :
index:全索引掃描,index與ALL區別為index類型只遍歷索引樹 這個連接類型對前面的表中的每一個記錄聯合進行完全掃描(比ALL更好,因為索引一般小於表數據)。 索引全表掃描,把索引從頭到尾掃一遍,常見於使用索引列就可以處理不需要讀取數據文件的查詢、可以使用索引排序或者分組的查詢。
#如:雖然where條件中沒有用到索引,但是要取出的列title是索引包含的列,所以只要全表掃描索引即可,直接使用索引樹查找數據
explain select title from film
ALL:全表掃描, MySQL將遍歷全表以找到匹配的行 這個連接類型對於前面的每一個記錄聯合進行完全掃描,這一般比較糟糕,應該盡量避免。這個就是全表掃描數據文件,然后再在server層進行過濾返回符合要求的記錄。
#如:當我們的where字段無索引時會全表掃描
explain extended sruelect * from film where rating > 9
possible_keys
指出MySQL能使用哪個索引在表中找到記錄,查詢涉及到的字段上若存在索引,則該索引將被列出,但不一定被查詢使用
該列完全獨立於EXPLAIN輸出所示的表的次序。這意味着在possible_keys中的某些鍵實際上不能按生成的表次序使用。
如果該列是NULL,則沒有相關的索引。在這種情況下,可以通過檢查WHERE子句看是否它引用某些列或適合索引的列來提高你的查詢性能。如果是這樣,創造一個適當的索引並且再次用EXPLAIN檢查查詢
Key
key列顯示MySQL實際決定使用的鍵(索引) select_type為index_merge時,這里可能出現兩個以上的索引,其他的select_type這里只會出現一個
如果沒有選擇索引,鍵是NULL。要想強制MySQL使用或忽視possible_keys列中的索引,在查詢中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。
key_len
表示索引中使用的字節數,可通過該列計算查詢中使用的索引的長度(key_len顯示的值為索引字段的最大可能長度,並非實際使用長度,即key_len是根據表定義計算而得,不是通過表內檢索出的)
用於處理查詢的索引長度,如果是單列索引,那就整個索引長度算進去,如果是多列索引,那么查詢不一定都能使用到所有的列,具體使用到了多少個列的索引,這里就會計算進去,沒有使用到的列,這里不會計算進去。留意下這個列的值,算一下你的多列索引總長度就知道有沒有使用到所有的列了。要注意,mysql的ICP特性使用到的索引不會計入其中。另外,key_len只計算where條件用到的索引長度,而排序和分組就算用到了索引,也不會計算到key_len中。
不損失精確性的情況下,長度越短越好
ref
表示上述表的連接匹配條件,即哪些列或常量被用於查找索引列上的值 如果是使用的常數等值查詢,這里會顯示const,如果是連接查詢,被驅動表的執行計划這里會顯示驅動表的關聯字段,如果是條件使用了表達式或者函數,或者條件列發生了內部隱式轉換,這里可能顯示為func
rows
表示MySQL根據表統計信息及索引選用情況,估算的找到所需的記錄所需要讀取的行數 這里是執行計划中估算的掃描行數,不是精確值
extra:
說明:extra列返回的描述的意義 該列包含MySQL解決查詢的詳細信息,有以下幾種情況:
Distinct :在select部分使用了distinc關鍵字 一旦mysql找到了與行相聯合匹配的行,就不再搜索了。 no tables used:不帶from字句的查詢或者From dual查詢 Not exists ?:mysql優化了LEFT JOIN,一旦它找到了匹配LEFT JOIN標准的行,就不再搜索了。 使用not in()形式子查詢或not exists運算符的連接查詢,這種叫做反連接。即,一般連接查詢是先查詢內表,再查詢外表,反連接就是先查詢外表,再查詢內表
Range checked for each Record(index map:#):沒有找到理想的索引,因此對從前面表中來的每一個行組合,mysql檢查使用哪個索引,並用它來從表中返回行。這是使用索引的最慢的連接之一。 Using filesort :看到這個的時候,查詢就需要優化了。mysql需要進行額外的步驟來查詢如何對返回row(行)排序。它根據連接類型以及存儲排序鍵值和匹配條件的全部行的行指針來排序全部行。排序時無法使用到索引時,就會出現這個。常見於order by和group by語句中(這是可能是ordery by,group by語句的結果,這可能是一個CPU密集型的過程,可以通過選擇合適的索引來改進性能,用索引來為查詢結果排序) Using index :查詢時不需要回表查詢,直接通過索引就可以獲取查詢的數據。,這發生在對表的全部的請求列都是同一個索引的部分的時候。 說明查詢是覆蓋了索引的,不需要讀取數據文件,從索引樹(索引文件)中即可獲得信息。如果同時出現using where,表明索引被用來執行索引鍵值的查找,沒有using where,表明索引用來讀取數據而非執行查找動作。這是MySQL服務層完成的,但無需再回表查詢記錄。 Using temporary :看到這個的時候,查詢需要優化了。表示使用了臨時表存儲中間結果,這通常發生在對不同的列集進行ORDER BY上,而不是GROUP BY上(常用於GROUP BY 和 ORDER BY操作中??)。 臨時表可以是內存臨時表和磁盤臨時表,執行計划中看不出來,需要查看status變量,used_tmp_table,used_tmp_disk_table才能看出來 Using where:列數據是從僅僅使用了索引中的信息而沒有讀取實際的行動的表返回的,這發生在對表的全部的請求列都是同一個索引的部分的時候,表示mysql服務器將在存儲引擎檢索行后再進行過濾 Using join buffer:改值強調了在獲取連接條件時沒有使用索引,並且需要連接緩沖區來存儲中間結果。如果出現了這個值,那應該注意,根據查詢的具體情況可能需要添加索引來改進能。 using join buffer(block nested loop),using join buffer(batched key accss):5.6.x之后的版本優化關聯查詢的BNL,BKA特性。主要是減少內表的循環數量以及比較順序地掃描查詢。 using sort_union,using_union,using intersect,using sort_intersection: using intersect:表示使用and的各個索引的條件時,該信息表示是從處理結果獲取交集 using union:表示使用or連接各個使用索引的條件時,該信息表示從處理結果獲取並集 using sort_union和using sort_intersection:與前面兩個對應的類似,只是他們是出現在用and和or查詢信息量大時,先查詢主鍵,然后進行排序合並后,才能讀取記錄並返回。 Impossible where:這個值強調了where語句會導致沒有符合條件的行。 Select tables optimized away:這個值意味着僅通過使用索引,優化器可能僅從聚合函數結果中返回一行 Where used :使用了WHERE從句來限制哪些行將與下一張表匹配或者是返回給用戶。如果不想返回表中的全部行,並且連接類型ALL或index,這就會發生,或者是查詢有問題。 using where:表示存儲引擎返回的記錄並不是所有的都滿足查詢條件,需要在server層進行過濾。查詢條件中分為限制條件和檢查條件,5.6之前,存儲引擎只能根據限制條件掃描數據並返回,然后server層根據檢查條件進行過濾再返回真正符合查詢的數據。5.6.x之后支持ICP特性,可以把檢查條件也下推到存儲引擎層,不符合檢查條件和限制條件的數據,直接不讀取,這樣就大大減少了存儲引擎掃描的記錄數量。extra列顯示注意:Extra列出現Using where表示MySQL服務器將存儲引擎返回服務層以后再應用WHERE條件過濾
using index condition:這是MySQL 5.6出來的新特性,叫做“索引條件推送”。簡單說一點就是MySQL原來在索引上是不能執行如like這樣的操作的,但是現在可以了,這樣減少了不必要的IO操作,但是只能用在二級索引上。 firstmatch(tb_name):5.6.x開始引入的優化子查詢的新特性之一,常見於where字句含有in()類型的子查詢。如果內表的數據量比較大,就可能出現這個 loosescan(m..n):5.6.x之后引入的優化子查詢的新特性之一,在in()類型的子查詢中,子查詢返回的可能有重復記錄時,就可能出現這個 除了這些之外,還有很多查詢數據字典庫,執行計划過程中就發現不可能存在結果的一些提示信息
select tables optimized away:在沒有GROUP BY子句的情況下,基於索引優化MIN/MAX操作,或者對於MyISAM存儲引擎優化COUNT(*)操作,不必等到執行階段再進行計算,查詢執行計划生成的階段即完成優化。
filtered
使用explain extended時會出現這個列,5.7之后的版本默認就有這個字段,不需要使用explain extended了。這個字段表示存儲引擎返回的數據在server層過濾后,剩下多少滿足查詢的記錄數量的比例,注意是百分比,不是具體記錄數。
partitions
explain partitions:相比 explain 多了個 partitions 字段,如果查詢是基於分區表的話,會顯示查詢將訪問的分區
因此,弄明白了explain語法返回的每一項結果,我們就能知道查詢大致的運行時間了,如果查詢里沒有用到索引、或者需要掃描的行過多,那么可以感到明顯的延遲。因此需要改變查詢方式或者新建索引。mysql中的explain語法可以幫助我們改寫查詢,優化表的結構和索引的設置,從而最大地提高查詢效率。當然,在大規模數據量時,索引的建立和維護的代價也是很高的,往往需要較長的時間和較大的空間,如果在不同的列組合上建立索引,空間的開銷會更大。因此索引最好設置在需要經常查詢的字段中。
mysql> explain select id from wy_size; +----+-------------+---------+-------+---------------+---------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+---------+-------+---------------+---------+---------+------+------+-------------+ | 1 | SIMPLE | wy_size | index | NULL | PRIMARY | 4 | NULL | 15 | Using index | +----+-------------+---------+-------+---------------+---------+---------+------+------+-------------+ 1 row in set mysql> explain select * from wy_size; +----+-------------+---------+------+---------------+------+---------+------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+---------+------+---------------+------+---------+------+------+-------+ | 1 | SIMPLE | wy_size | ALL | NULL | NULL | NULL | NULL | 15 | | +----+-------------+---------+------+---------------+------+---------+------+------+-------+ 1 row in set mysql> explain select * from wy_size where id=5 ; +----+-------------+---------+-------+---------------+---------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+---------+-------+---------------+---------+---------+-------+------+-------+ | 1 | SIMPLE | wy_size | const | PRIMARY | PRIMARY | 4 | const | 1 | | +----+-------------+---------+-------+---------------+---------+---------+-------+------+-------+ 1 row in set