聯合索引這點事兒

我們從頭開始

ER圖

在這裏插入圖片描述

建表

按照ER圖,建立數據庫和表,並且進行測試數據的填充。(建表sql和填充腳本的文件可公衆號(Vegout)回覆關鍵字“聯合索引”獲取)
在這裏插入圖片描述

sql優化——建索引

1、查詢所有標題以title666開頭的文章

select * from article where title like "title666%"

結果

已找到記錄: 1,111  警告: 0  持續時間 1 查詢: 0.688 sec

用了0.688秒,下面我們給title字段加上索引

alter table article add key titleindex(title);

再次執行select語句(記得清除緩存reset query cache),瞬間查出

已找到記錄: 1,111  警告: 0  持續時間 1 查詢: 0.000 sec.

但如果like條件這樣寫

select * from article where title like "%itle666%"

因爲我們測試數據article中的所有title都是以“title”開頭的,所以這樣寫,查出的數據是一樣的,但是

已找到記錄: 1,111  警告: 0  持續時間 1 查詢: 0.656 sec.

又使用了0.656秒,通過explain我們可以看到
在這裏插入圖片描述
這次查詢並沒有走索引。所以建立索引的字段在like條件下,如果以“%”開頭,索引會失效。

2、查詢title以“title666”開頭並且summary以“summary666”開頭的所有文章
我們執行

select * from article where title like "title666%" 
and content like "content666%"

耗時

已找到記錄: 1,111  警告: 0  持續時間 1 查詢: 0.594 sec.

我們給title和summary建立一個聯合索引

alter table article add key title_summary_index(title,summary)

再次執行select語句,耗時

已找到記錄: 1,111  警告: 0  持續時間 1 查詢: 0.031 sec

但此時如果我們只查詢summary like"summary666"的記錄,將不會走索引

select * from article where summary like "summary666%"
已找到記錄: 1,111  警告: 0  持續時間 1 查詢: 0.672 sec.

對與聯合索引title_summary_index來說,遵循最左前綴匹配原則,只有先走了title的索引,纔會再走summaruy的索引。這裏只有summary是查詢條件,將不會走索引。也就是對與聯合索引(a,b),查詢a會走索引,查詢a,b也會走索引,但查詢b不會走索引。還有就是,對與聯合索引中的字段出現位置,比如查詢a,b,還是b,a,並沒有嚴格的要求,也就是說我們這樣寫,也會走索引

select * from article where summary like "summary666%" 
and title like "title666%" 

爲了進一步說明最左匹配原則,我們再建一個索引(並刪除上一個聯合索引)

alter table article add key 
time_title_summary_index(publish_time,title,summary)

這個索引加入了發表時間,並放在了首位,也就是說只有publish_time 先走了索引,後邊的兩個字段纔有機會走索引。

select * from article where summary like "summary666%" 
and title like "title666%" and publish_time>'2018-10-20 21:42:20'

在這個sql中,publish_time走不了索引,於是聯合索引失效,只能進行全表掃描。這裏使之失效的查詢條件是publish_time>‘2018-10-20 21:42:20’,並不是說使用“>”就會失效,mysql中使用了“!=”,“<>”,“not in”,“not exist”會使索引失效,但對於“>”,“<”,“>=”,“<=”的使用,優化器會根據查詢的數據情況來決定走不走索引(走索引快就走索引,索引慢就全表掃描),比如這裏將大於號改成小於號

select * from article where summary like "summary666%" 
and title like "title666%" and publish_time<'2018-10-20 21:42:20'

很愉快的走了索引
在這裏插入圖片描述
由此你也可以推斷,庫中pulish_time小於2018-10-20 21:42:20的一定比少,不錯,只有七百多,大於它的有不到一百萬條。在一個博客上曾看見這麼一段話形如聯合索引:聯合索引就像是一路關斬將,對與聯合索引(a,b,c),a就是第一關,b是第二關,c是第三關,關得一個一個按順序來過(大致這麼個意思)。感覺形如的還真是恰當。
如果當時我們在沒有刪除第一個聯合索引的情況下,執行上邊沒有走索引的select語句,就是這個

select * from article where summary like "summary666%" 
and title like "title666%" and publish_time>'2018-10-20 21:42:20'

我們將會發現,它會走我們創建的第一個聯合索引。也就是publish_time使得不能夠走第二個聯合索引,但publish_time之後的條件可以走第一個聯合索引。

當然,我們也可以在title,summary上分別建立單列索引,但當多條件查詢時,只能有一個索引生效。我們給這兩個字段分別建立索引,然後執行這個sql

 explain select * from article where summary like 
 "summary666%" and title like "title666%"

我們發現
在這裏插入圖片描述
只走了一個索引。但單列索引也有他的好處,比如如果是條件是or的關係,兩個索引就都可以走

 explain select * from article where summary like 
 "summary666%" or title like "title666%"

在這裏插入圖片描述
而如果我們使用是剛纔的聯合索引,or將會使聯合索引失效
在這裏插入圖片描述

總結

  1. 多條件查詢時,單列索引只能用到一個,此時應該選擇聯合索引
  2. 聯合索引遵循最左前綴匹配原則,只有左側先走了索引,之後的字段纔有可能走索引。所以建立聯合索引的時候,一定要注意順序,字段使用越頻繁越要靠左。這個順序指的是創建索引時的順序,至於sql查詢語句中的順序沒有要求,因爲mysql會對這個順序進行優化調整以滿足索引的要求。“%…”,“!=”,“<>”,“not in”,“not exist”,“or”,“is null”,“is not null”使索引失效,“>”,“<”,“>=”,“<=”有可能使索引失效。
  3. 聯合索引的本質:當建立了(a,b,c)聯合索引時,相當於創建了(a)單列索引,(a,b)聯合索引,(a,b,c)聯合索引。
  4. 什麼情況下應該建立索引:選擇性高的字段,經常where查詢的字段,穩定的字段
  5. 什麼情況下不要建立索引:頻繁變化的字段,選擇性低的字段

注:插入測試數據的腳本大約會運行10分鐘,插入300多萬條數據。文中測試sql涉及到publish_time字段的地方需要修改成你運行腳本時插入的時間。
抱歉:建了那麼多表,文中只用了一個,我原來以爲都會用到了,捂臉。給自己開脫一下,萬一以後文章用到了嘞。哈哈

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章