explain顯示了mysql如何使用索引來處理select語句以及鏈接表。能夠幫助選擇更好的索引和寫出更優化的查詢語句。mysql
先解析一條sql語句,看出現什麼內容算法
EXPLAINSELECTs.uid,s.username,s.name,f.email,f.mobile,f.phone,f.postalcode,f.address
FROM uchome_space ASs,uchome_spacefieldASf
WHERE 1
AND s.groupid=0
AND s.uid=f.uid
sql
1. idmysql優化
SELECT識別符。這是SELECT查詢序列號。這個不重要,查詢序號即爲sql語句執行的順序,看下面這條sql函數
EXPLAINSELECT*FROM(
SELECT* FROMuchome_space LIMIT10)ASsoop
它的執行結果爲post
能夠看到這時的id變化了優化
2.select_typeui
select類型,它有如下幾種值spa
2.1 simple 它表示簡單的select,沒有union和子查詢
2.2 primary 最外面的select,在有子查詢的語句中,最外面的select查詢就是primary,上圖中就是這樣
2.3 union union語句的第二個或者說是後面那一個.現執行一條語句,explain
select * from uchome_space limit 10 union select * from uchome_space limit 10,10
會有以下結果
第二條語句使用了union
2.4 dependent union UNION中的第二個或後面的SELECT語句,取決於外面的查詢
2.5 union result UNION的結果,如上面所示
還有幾個參數,這裏就不說了,不重要
3 table
輸出的行所用的表,這個參數顯而易見,容易理解
4 type
鏈接類型。有多個參數,先從最佳類型到最差類型介紹 重要且困難
4.1 system
表僅有一行,這是const類型的特列,平時不會出現,這個也能夠忽略不計
4.2 const
表最多有一個匹配行,const用於比較primary key 或者unique索引。由於只匹配一行數據,因此很快
記住必定是用到primary key 或者unique,而且只檢索出兩條數據的 狀況下才會是const,看下面這條語句
explain SELECT * FROM `asj_admin_log` limit 1,結果是
雖然只搜索一條數據,可是由於沒有用到指定的索引,因此不會使用const.繼續看下面這個
explain SELECT * FROM `asj_admin_log` where log_id = 111
log_id是主鍵,因此使用了const。因此說能夠理解爲const是最優化的
4.3 eq_ref
對於eq_ref的解釋,mysql手冊是這樣說的:"對於每一個來自於前面的表的行組合,從該表中讀取一行。這多是最好的聯接類型,除了const類型。它用在一個索引的全部部分被聯接使用而且索引是UNIQUE或PRIMARY KEY"。eq_ref能夠用於使用=比較帶索引的列。看下面的語句
explain select * from uchome_spacefield,uchome_space where uchome_spacefield.uid = uchome_space.uid
獲得的結果是下圖所示。很明顯,mysql使用eq_ref聯接來處理uchome_space表。
目前的疑問:
4.3.1 爲何是隻有uchome_space一個表用到了eq_ref,而且sql語句若是變成
explain select * from uchome_space,uchome_spacefield where uchome_space.uid = uchome_spacefield.uid
結果仍是同樣,須要說明的是uid在這兩個表中都是primary
4.4 ref 對於每一個來自於前面的表的行組合,全部有匹配索引值的行將從這張表中讀取。若是聯接只使用鍵的最左邊的前綴,或若是鍵不是UNIQUE或PRIMARY KEY(換句話說,若是聯接不能基於關鍵字選擇單個行的話),則使用ref。若是使用的鍵僅僅匹配少許行,該聯接類型是不錯的。
看下面這條語句 explain select * from uchome_space where uchome_space.friendnum = 0,獲得結果以下,這條語句能搜出1w條數據
4.5 ref_or_null 該聯接類型如同ref,可是添加了MySQL能夠專門搜索包含NULL值的行。在解決子查詢中常用該聯接類型的優化。
上面這五種狀況都是很理想的索引使用狀況
4.6 index_merge 該聯接類型表示使用了索引合併優化方法。在這種狀況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。
4.7 unique_subquery
4.8 index_subquery
4.9 range 給定範圍內的檢索,使用一個索引來檢查行。看下面兩條語句
explain select * from uchome_space where uid in (1,2)
explain select * from uchome_space where groupid in (1,2)
uid有索引,groupid沒有索引,結果是第一條語句的聯接類型是range,第二個是ALL.覺得是必定範圍因此說像 between也能夠這種聯接,很明顯
explain select * from uchome_space where friendnum = 17
這樣的語句是不會使用range的,它會使用更好的聯接類型就是上面介紹的ref
4.10 index 該聯接類型與ALL相同,除了只有索引樹被掃描。這一般比ALL快,由於索引文件一般比數據文件小。(也就是說雖然all和Index都是讀全表,但index是從索引中讀取的,而all是從硬盤中讀的)
當查詢只使用做爲單索引一部分的列時,MySQL可使用該聯接類型。
4.11 ALL 對於每一個來自於先前的表的行組合,進行完整的表掃描。若是表是第一個沒標記const的表,這一般很差,而且一般在它狀況下很差。一般能夠增長更多的索引而不要使用ALL,使得行能基於前面的表中的常數值或列值被檢索出。
5 possible_keys 提示使用哪一個索引會在該表中找到行,不過重要
6 keys MYSQL使用的索引,簡單且重要
7 key_len MYSQL使用的索引長度
8 ref ref列顯示使用哪一個列或常數與key一塊兒從表中選擇行。
9 rows 顯示MYSQL執行查詢的行數,簡單且重要,數值越大越很差,說明沒有用好索引
10 Extra 該列包含MySQL解決查詢的詳細信息。
10.1 Distinct MySQL發現第1個匹配行後,中止爲當前的行組合搜索更多的行。一直沒見過這個值
10.2 Not exists
10.3 range checked for each record
沒有找到合適的索引
10.4 using filesort
MYSQL手冊是這麼解釋的「MySQL須要額外的一次傳遞,以找出如何按排序順序檢索行。經過根據聯接類型瀏覽全部行併爲全部匹配WHERE子句的行保存排序關鍵字和行的指針來完成排序。而後關鍵字被排序,並按排序順序檢索行。」目前不太明白
10.5 using index 只使用索引樹中的信息而不須要進一步搜索讀取實際的行來檢索表中的信息。這個比較容易理解,就是說明是否使用了索引
explain select * from ucspace_uchome where uid = 1的extra爲using index(uid建有索引)
explain select count(*) from uchome_space where groupid=1 的extra爲using where(groupid未創建索引)
10.6 using temporary
爲了解決查詢,MySQL須要建立一個臨時表來容納結果。典型狀況如查詢包含能夠按不一樣狀況列出列的GROUP BY和ORDER BY子句時。
出現using temporary就說明語句須要優化了,舉個例子來講
EXPLAIN SELECT ads.id FROM ads, city WHERE city.city_id = 8005 AND ads.status = 'online' AND city.ads_id=ads.id ORDER BY ads.id desc
id select_type table type possible_keys key key_len ref rows filtered Extra
------ ----------- ------ ------ -------------- ------- ------- -------------------- ------ -------- -------------------------------
1 SIMPLE city ref ads_id,city_id city_id 4 const 2838 100.00 Using temporary; Using filesort
1 SIMPLE ads eq_ref PRIMARY PRIMARY 4 city.ads_id 1 100.00 Using where
這條語句會使用using temporary,而下面這條語句則不會
EXPLAIN SELECT ads.id FROM ads, city WHERE city.city_id = 8005 AND ads.status = 'online' AND city.ads_id=ads.id ORDER BY city.ads_id desc
id select_type table type possible_keys key key_len ref rows filtered Extra
------ ----------- ------ ------ -------------- ------- ------- -------------------- ------ -------- ---------------------------
1 SIMPLE city ref ads_id,city_id city_id 4 const 2838 100.00 Using where; Using filesort
1 SIMPLE ads eq_ref PRIMARY PRIMARY 4 city.ads_id 1 100.00 Using where
這是爲何呢?他倆之間只是一個order by不一樣,MySQL 表關聯的算法是 Nest Loop Join,是經過驅動表的結果集做爲循環基礎數據,而後一條一條地經過該結果集中的數據做爲過濾條件到下一個表中查詢數據,而後合併結果。EXPLAIN 結果中,第一行出現的表就是驅動表(Important!)以上兩個查詢語句,驅動表都是 city,如上面的執行計劃所示!
對驅動表能夠直接排序,對非驅動表(的字段排序)須要對循環查詢的合併結果(臨時表)進行排序(Important!)
所以,order by ads.id desc 時,就要先 using temporary 了!
驅動表的定義
wwh999 在 2006年總結說,當進行多表鏈接查詢時, [驅動表] 的定義爲:
1)指定了聯接條件時,知足查詢條件的記錄行數少的表爲[驅動表];
2)未指定聯接條件時,行數少的表爲[驅動表](Important!)。
永遠用小結果集驅動大結果集
今天學到了一個很重要的一點:當不肯定是用哪一種類型的join時,讓mysql優化器自動去判斷,咱們只需寫select * from t1,t2 where t1.field = t2.field
10.7 using where
WHERE子句用於限制哪個行匹配下一個表或發送到客戶。除非你專門從表中索取或檢查全部行,若是Extra值不爲Using where而且表聯接類型爲ALL或index,查詢可能會有一些錯誤。(這個說明不是很理解,由於不少不少語句都會有where條件,而type爲all或index只能說明檢索的數據多,並不能說明錯誤,useing where不是很重要,可是很常見)
若是想要使查詢儘量快,應找出Using filesort 和Using temporary的Extra值。
10.8 Using sort_union(...), Using union(...),Using intersect(...)
這些函數說明如何爲index_merge聯接類型合併索引掃描
10.9 Using index for group-by
相似於訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引,能夠用來查詢GROUP BY或DISTINCT查詢的全部列,而不要額外搜索硬盤訪問實際的表。而且,按最有效的方式使用索引,以便對於每一個組,只讀取少許索引條目。
實例講解
經過相乘EXPLAIN輸出的rows列的全部值,你能獲得一個關於一個聯接如何的提示。這應該粗略地告訴你MySQL必須檢查多少行以執行查詢。當你使用max_join_size變量限制查詢時,也用這個乘積來肯定執行哪一個多表SELECT語句。