explain主要用於sql語句中的select查詢,可以顯示的查看該sql語句索引的命中情況,從而更好的利用索引、優化查詢效率。
Explain語法如下:explain [extended] select ...
其中extended是選用的,如果使用的extended,那麼explain之後就可以使用show warnings查看相應的優化信息,也就是mysql內部實際執行的query。
列名
描述
說明
相關鏈接
id
若沒有子查詢和聯合查詢,id則都是1。
Mysql會按照id從大到小的順序執行query,在id相同的情況下,則從上到下執行。
select_type
select類型。
常見類型
table
輸出的行所引用的表。
有時看到的是<derivedN>,其中N對應的是id列的值。
type
Mysql的存取方法,連接訪問類型。
常見類型
possible_keys
在查詢過程中可能用到的索引。
在優化初期創建該列,但在以後的優化過程中會根據實際情況進行選擇,所以在該列列出的索引在後續過程中可能沒用。該列為NULL意味著沒有相關索引,可以根據實際情況看是否需要加索引。
key
訪問過程中實際用到的索引。
有可能不會出現在possible_keys中(這時可能用的是覆蓋索引,即使query中沒有where)。possible_keys揭示哪個索引更有效,key是優化器決定哪個索引可能最小化查詢成本,查詢成本基於系統開銷等總和因素,有可能是“執行時間”矛盾。如果強制mysql使用或者忽略possible_keys中的索引,需要在query中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。
key_len
顯示使用索引的字節數。
由根據表結構計算得出,而不是實際數據的字節數。如ColumnA(char(3)) ColumnB(int(11)),在utf-8的字符集下,key_len=3*3+4=13。計算該值時需要考慮字符列對應的字符集,不同字符集對應不同的字節數。
mysql5.1.5下latin1、utf8、gbk字符數、字節數、漢字的對應關系
ref
顯示了哪些字段或者常量被用來和 key
配合從表中查詢記錄出來。顯示那些在index查詢中被當作值使用的在其他表裡的字段或者constants。
rows
估計為返回結果集而需要掃描的行。
不是最終結果集的函數,把所有的rows乘起來可估算出整個query需要檢查的行數。有limit時會不准確。(為毛?)
Extra
mysql查詢的附加信息。
常見信息
select類型:
simple:query中不包含子查詢或聯合查詢。
primary:包含子查詢或聯合查詢的query中,最外層的select查詢。
subquery:子查詢在select的目標裡,不在from中,子查詢的第一個select。
例如:EXPLAIN SELECT (SELECT actor_id FROM actor) FROM film_actor
dependent subquery:子查詢內層的第一個select,依賴於外部查詢的結果集。
例如:EXPLAIN SELECT * FROM actor WHERE actor_id IN (SELECT actor_id FROM film_actor)
EXPLAIN SELECT * FROM actor WHERE actor_id IN (SELECT actor_id FROM film_actor WHERE actor_id=1)
EXPLAIN SELECT * FROM actor WHERE actor_id = (SELECT actor_id FROM film_actor WHERE actor_id=1)
uncacheable subquery:表示子查詢,但返回結果不能被cache,必須依據外層查詢重新計算。(在什麼情況下會出現這個?)
derived:子查詢在from子句中,執行查詢的時候會把子查詢的結果集放到臨時表(衍生表)。
例如:EXPLAIN SELECT * FROM (SELECT * FROM actor) AS a。此時table列會顯示<derivedN>,其中N對應id列的值。
union:在聯合查詢中第二個及其以後的select對應的類型。
例如:EXPLAIN SELECT * FROM film_actor UNION ALL SELECT * FROM actor
如果union包含在一個from子查詢裡面,則from子查詢中的第一個select標記為derived。
例如:EXPLAIN SELECT * FROM ( SELECT * FROM film_actor UNION ALL SELECT * FROM actor) a
union result:從union臨時表獲取結果集合。例如上面兩個查詢結果集中的最後一行。<union1,2,...>其中1,2,...所標識的id列表代表id列,當id列表長度超過20個之後就會省略後面的<union1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,...>。例子如上圖。
dependent union:子查詢中的union,且為union中第二個select開始的後面所有select,同樣依賴於外部查詢的結果集。
例如:EXPLAIN SELECT * FROM actor WHERE actor_id IN (SELECT actor_id FROM film_actor UNION ALL SELECT actor_id FROM film_actor)
uncacheable union:表示union第二個或以後的select,但結果不能被cache,必須依據外層查詢重新計算。(在什麼情況下會出現)
按照效率從高到低給出幾種常見的type類型:
NULL:mysql在優化過程中分解query,執行時甚至不用再訪問表數據或者索引,比如id=-1。
例如:EXPLAIN SELECT * FROM actor WHERE actor_id = -1
system:查詢的表僅有一行。這是const聯接類型的一個特例。(在沒有任何索引的情況下,只有一條數據,MyISAM會顯示system,InnoDB會顯示ALL)
const:最多會有一條記錄匹配。因為僅有一行,在這行的列值可被優化器剩余部分認為是常數。const表很快,因為它們只讀取一次。發生在有一個unique key或者主鍵,並且where子句給它設定了一個比較值。
例如:EXPLAIN SELECT * FROM actor WHERE actor_id = 1(其中actor_id是主鍵)
eq_ref:使用這種索引查找,最多返回一條符合條件的記錄。會在使用主鍵或者唯一性索引訪問數據時看到,除了const類型這可能是最好的聯接類型。
例如:EXPLAIN SELECT * FROM actor, actorsex WHERE actor.actor_id = actorsex.actor_id(其中actor_id是actor、actorsex的主鍵,且actorsex中只有一條記錄,如果多於一條記錄就不是eq_ref)
ref:這是一種索引訪問。只有當使用一個非唯一性索引或者唯一性索引的非唯一性前綴(換句話說,就是無法根據該值只取得一條記錄)時才會發生,將索引和某個值相比較,這個值可能是一個常數,也可能是來自前一個表裡的多表查詢的結果值。如果使用的鍵僅僅匹配少量行,該聯接類型是不錯的。
例如:EXPLAIN SELECT * FROM film_actor,actor WHERE film_actor.actor_id=actor.actor_id AND film_actor.actor_id=1
ref_or_null:類似ref。不同的是Mysql會在檢索的時候額外的搜索包含 NULL 值的記錄,他意味著mysql必須進行二次查找,在初次查找的結果中找出NULL條目。
index_merge:查詢中使用兩個或多個索引,然後對索引結果進行合並。在這種情況下,key列包含所有使用的索引,key_len包含這些索引的最長的關鍵元素。
select * from test where column1 = 1 or column2 = 2(沒試出來!555555)
unique_subquery:用來優化有子查詢的in,並且該子查詢是通過一個unique key選擇的。子查詢返回的字段組合是主鍵或者唯一索引。
例如:EXPLAIN SELECT * FROM actor WHERE actor_id IN (SELECT actor_id FROM actor)
index_subquery:該聯接類型類似於unique_subquery,子查詢中的返回結果字段組合是一個索引或索引組合,但不是一個主鍵或者唯一索引。
例如:EXPLAIN SELECT * FROM film_actor WHERE film_id IN (SELECT film_id FROM film_actor)
range:在一定范圍內掃描索引。如where中帶有between或者>,此時ref列為NULL。當使用=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN操作符,用常量比較關鍵字列時,可以使用range。
index:按索引次序掃描數據。因為按照索引掃描所以會避免排序,但也會掃描整表數據,若隨機讀取開銷會更大。如果extra列顯示using index,說明使用的是覆蓋索引(覆蓋索引:包含所有滿足查詢需要的數據列的索引)。對於InnoDB表特別有用,此時只訪問索引數據即可,不用再根據主鍵信息獲取原數據行,避免了二次查詢,而MyISAM表優化效果相對InnoDB來說沒有那麼的明顯。
all:按行掃描全表數據,除非查詢中有limit或者extra列顯示使用了distinct或notexists等限定詞。
Extra信息 :
distinct:當mysql找到第一條匹配的結果值時,就停止該值的查詢,然後繼續該列其他值的查詢。
not exists:在左連接中,優化器可以通過改變原有的查詢組合而使用的優化方法。當發現一個匹配的行之後,不再為前面的行繼續檢索,可以部分減少數據訪問的次數。例如,表t1、t2,其中t2.id為not null,對於SELECT * FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;由於 t2.id非空,所以只可能是t1中有,而t2中沒有,所以其結果相當於求差。left join原本是要兩邊join,現在Mysql優化只需要依照 t1.id在t2中找到一次t2.id即可跳出。
const row not found:涉及到的表為空表,裡面沒有數據。
Full scan on NULL key:是優化器對子查詢的一種優化方式,無法通過索引訪問NULL值的時候會做此優化。
Impossible Having:Having子句總是false而不能選擇任何列。例如having 1=0
Impossible WHERE:Where子句總是false而不能選擇任何列。例如where 1=0
Impossible WHERE noticed after reading const tables:mysql通過讀取“const/system tables”,發現Where子句為false。也就是說:在where子句中false條件對應的表應該是const/system tables。這個並不是mysql通過統計信息做出的,而是真的去實際訪問一遍數據後才得出的結論。當對某個表指定了主鍵或者非空唯一索引上的等值條件,一個query最多只可能命中一個結果,mysql在explain之前會優先根據這一條件查找對應記錄,並用記錄的實際值替換query中所有用到來自該表屬性的地方。
例如:select * from a,b where a.id = 1 and b.name = a.name
執行過程如下:先根據a.id = 1找到一條記錄(1, 'name1'),然後將b.name換成'name1',然後通過a.name = 'name1'查找,發現沒有命中記錄,最終返回“Impossible WHERE noticed after reading const tables”。
No matching min/max row:沒有行滿足如下的查詢條件。
例如:EXPLAIN SELECT MIN(actor_id) FROM actor WHERE actor_id > 3(只有兩條記錄)
actor_id為唯一性索引時,會顯示“No matching min/max row”,否則會顯示“using where”。
no matching row in const table:對一個有join的查詢,包含一個空表或者沒有數據滿足一個唯一索引條件。
No tables used:查詢沒有From子句,或者有一個From Dual(dual:虛擬表,是為了滿足select...from...習慣)子句。
例如:EXPLAIN SELECT VERSION()
Range checked for each record (index map: N):Mysql發現沒有好的index,但發現如果進一步獲取下一張join表的列的值後,某些index可以通過range等使用。Mysql沒找到合適的可用的索引。取代的辦法是,對於前一個表的每一個行連接,它會做一個檢驗以決定該使用哪個索引(如果有的話),並且使用這個索引來從表裡取得記錄。這個過程不會很快,但總比沒有任何索引時做表連接來得快。
Select tables optimized away:當我們使用某些聚合函數來訪問存在索引的某個字段時,優化器會通過索引直接一次定位到所需要的數據行完成整個查詢。在使用某些聚合函數如min, max的query,直接訪問存儲結構(B樹或者B+樹)的最左側葉子節點或者最右側葉子節點即可,這些可以通過index解決。Select count(*) from table(不包含where等子句),MyISAM保存了記錄的總數,可以直接返回結果,而Innodb需要全表掃描。Query中不能有group by操作。
unique row not found:對於SELECT … FROM tbl_name,沒有行滿足unique index或者primary key。從表中查詢id不存在的一個值會顯示Impossible WHERE noticed after reading const tables。
Using filesort:指Mysql將用外部排序而不是按照index順序排列結果。數據較少時從內存排序,否則從磁盤排序。Explain不會顯示的告訴客戶端用哪種排序。
Using index:表示Mysql使用覆蓋索引避免全表掃描,不需要再到表中進行二次查找數據。注意不要和type中的index類型混淆。
Using index for group-by:類似Using index,所需數據只需要讀取索引,當query中有group by或distinct子句時,如果分組字段也在索引中,extra就會顯示該值。
Using temporary:Mysql將創建一個臨時表來容納中間結果。在group by和order by的時,如果有必要的話。例如group by一個非鍵列,優化器會創建一個臨時表,有個按照group by條件構建的unique key,然後對於每條查詢結果(忽略group by),嘗試insert到臨時表中,如果由於unique key導致insert失敗,則已有的記錄就相應的updated。例如,name上沒有索引,SELECT name,COUNT(*) FROM product GROUP BY name,為了排序,Mysql就需要創建臨時表。此時一般還會顯示using filesort。
Using where:表示Mysql將對storage engine提取的結果進行過濾。例如,price沒有index,SELECT * FROM product WHERE price=1300.00。有許多where的條件由於包含了index中的列,在查找的時候就可以過濾,所以不是所有帶where子句的查詢會顯示Using where。
Using join buffer:5.1.18版本以後才有的值。join的返回列可以從buffer中獲取,與當前表join。
例如:explain select * from t1,t2 where t1.col < 10 and t2.col < 10
Scanned N databases:指在處理information_schema查詢時,有多少目錄需要掃描。
例如:EXPLAIN SELECT TABLE_NAME, ROW_FORMAT FROM INFORMATION_SCHEMA.TABLES
網上說這個查詢會顯示Scanned all databases,我試了下extra列是空。
Skip_open_table, Open_frm_only, Open_trigger_only, Open_full_table:指示從information_schema查詢信息時有關文件開啟的優化。 Skip_open_table:表信息已經獲得,不需要打開。 Open_frm_only:只打開.frm文件。 Open_trigger_only:只打開.trg文件。 Open_full_table:沒有優化。.frm,.myd和.myi文件都打開。
Using sort_union(…), Using union(…), Using intersect(…):都出現在index_merge讀取類型中。 Using sort_union:用兩個或者兩個以上的key提取數據,但優化器無法確保每個key會提取到一個自然排好序的結果,所以為了排除多余的數據,需要額外的處理。例如,customer的state,(lname,fname)是key,但lname不是key,SELECT COUNT(*) FROM customer WHERE (lname = ‘Jones') OR (state = ‘UT'),由於lname上面沒有key,所以使用(lname,fname),使得結果可能不按照順序,優化器需要額外的一些工作。 Using union:用兩個或者兩個以上的key提取數據,分別取得結果是已排序,通過合並就可以獲得正確結果。例如,customer中的state和(lname,fname)是key,SELECT COUNT(state) FROM customer WHERE (lname = ‘Jones' AND fname='John') OR (state = ‘UT')。 Using intersect:用兩個或者兩個以上的key提取數據,分別取得結果是已排序,通過求交就可以獲得正確結果。例如,customer中的state和(lname,fname)是key,SELECT COUNT(state) FROM customer WHERE (lname = ‘Jones' AND fname='John') AND (state = ‘UT')。
Using where with pushed condition:僅用在ndb上。Mysql Cluster用Condition Pushdown優化改善非索引字段和常量之間的直接比較。condition被pushed down到cluster的數據節點,並在所有數據節點同時估算,把不合條件的列剔除避免網絡傳輸。
mysql5.1.5下latin1、utf8、gbk字符數、字節數、漢字的對應關系:
latin1:
1character=1byte, 1漢字=2character 一個字段定義成varchar(200),可以存儲100個漢字或者200個字符,占用200個字節。尤其是當字段內容是字母和漢字組成時,盡量假設字段內容都是由漢字組成,據此來設置字段長度。
utf8:
1character=3bytes, 1漢字=1character一個字段定義成 varchar(200),則它可以存儲200個漢字或者200個字母,占用600個字節。
gbk:
1character=2bytes,1漢字=1character一個字段定義成 varchar(200),則它可以存儲200個漢字或者200個字母,占用400個字節。
word版打包下載