避免索引失效原則(一)
精力有限,剩余的失效原則將會在 《避免索引失效原則(二)》中連載出來,請諒解
作者 : Stanley 羅昊
【轉載請注明出處和署名,謝謝!】
避免索引失效的一些原則
我們編寫SQL語句后會進行添加一些索引進行優化,但是有時候確實建了索引,但索引有時候會失效;
比如在模糊查詢使用 in 關鍵字的時候索引就失效了,這只是其中的一個條件;
1.復合索引的時候,不要跨列或無序使用(最佳左前綴)
我在前幾篇文章有重點介紹過;
就比如你建立了一個索引 分別字段為 a b c,你使用的時候卻沒有從a開始向后依次使用,而是使用了a c 把中間的b漏掉了下面我舉個例子:
比如我 where a ... and b ... order by c,這種使用順序就符合最佳做前綴,我從左向右依次使用了索引,如果你寫成下面這樣:
where b ... and a order by c,這樣很明顯你順序不對,並不滿足最佳左前綴,從而導致了索引失效;
2.復合索引,盡量使用全索引匹配
假設我現在建立了一個復合索引 a b c,在查詢的時候,盡量把這些索引字段都用上;
比如我現在想找一個張三,你先根據 a 找,再根據b找,最后再根據c找,這樣找就會更快一點,盡量不要你建了三個索引你卻只用兩個,這樣雖然可以,但是卻把一級目錄給刪了;
就跟看書一樣,我要找書上一個精確內容,准確來說先看目錄,再看章節,再看最后的小結,道理是一樣的;
3.不要在索引上進行任何操作
如果你在索引上進行任何操作,索引就必將失效,什么是任何操作,下發我將舉例說明:
比如你對索引進行加減乘除計算,進行一些函數計算,或進行一些類型轉換,在這種情況下,索引都會失效;
比如我select ... where A.x = ...;簡單寫一個這樣的就行了,不要再進行一些花里胡哨的操作,這里假設A.x是索引:
你不要寫成:select... where A.x*3 = ....;即是是索引,你算完之后就失效了,就不要這樣干!
這里就給大家演示一下:我現在編寫一條SQL語句記得前面加explain:
select * from book where authroid = 1 and typeid = 2;
首先book表中的 authroid 跟 typeid 均是索引:
通過key_len可以清楚的發現我用到了兩個索引,一個是四,兩個加起來就是八,這兩個索引本別是authroid typeid ,而且查詢效率是ref級別,接下來我就對它進行一些操作;
explain select * from book where authroid = 1 and typeid*2 = 2;
執行結果:
雖然我們的查詢級別仍然是ref,但是值得注意的是,key_len變成了四,我明明寫了兩個索引,現在卻少了一個,明明有兩個索引,你卻用了一個,原因很簡單,因為我在typeid上進行乘法操作了!
如果還不能明白,我這次把這兩個索引字段都進行操作:
explain select * from book where authroid*2 = 1 and typeid*2 = 2;
執行結果:
這個結果夠明顯了把,查詢級別變成了ALL,而且我明明有兩個索引,卻一個都沒有用!所以從這里面就能得出結論,不能對索引進行任何操作,否則就會導致索引失效!
4.對於復合索引左邊失效右邊全部失效
現在我們對上一條SQL語句再進行更改操作:
select * from book where authroid*2 = 1 and typeid = 2;
這條SQL語句authroid typeid 這兩個字段是復合索引,我現在給authroid字段進行操作,下面我們看執行結果:
我即便沒有對typid進行任何操作,但是導致的結果卻是全部失效!
原因很簡單,在復合索引下,你左前第一個失效,那么你后面全部跟着失效;
假設有 a b c 這些字段是復合索引,我給a 字段進行乘法操作,那么b c 字段都將會失效;
給b加字段,b后面的全部字段都會失效,a不受影響;
這里值得一提的是,如果有兩個復合索引,比如 a1 a2是一個復合索引,b1 b2也是一個復合索引,即便a1在左邊a1失效了a2會跟着失效但是b1 b2不受影響,因為復合索引與復合索引之間是沒有任何關系的;
5.復合索引不能使用不等於(!= 或 <> is null (is not null))
如果用以上其中一種,會導致資深以及右側索引全部失效,下面我將會舉例說明:
我現在編寫一條SQL語句j記得前面加上explain :
select * from book where authoid = 1 and typeid = 2
其中authoid typeid 均是復合索引:
執行結果發現一些異常現象,首先key里面只生效了一個,在key_len里面是4不是8,因為我用了兩個索引應該是8才對,我也沒有對索引進行操作,但就是失效了一個;
原因:SQL優化是一種概率層面的優化,至於是否實際使用了我們的優化,需要通過explaini進行推測,在possible_keys中我們可以看到,它預測使用了兩個索引,但實際它就是只用了一個,因為MySQL優化是概率的,即便你手動優化的很少,有時你照樣正常生效,這正常現象,因為手動優化試只是概率;
現在我們不管概率問題,我們繼續緊接着上剛才的例子;
我們看到authroid仍在生效,我們這次把authroid進行一些不等於操作:
explain select * from book where authoid ! = 1 and typeid = 2
執行結果:
奇怪的事情又發生了,這次查詢級別仍是fef但是我們發現authoid確實失效了,但是typeid生效了;
原來authoid失效只是你自身失效了,並不影響其他字段的生效概率,也可以理解為typeid把authoid給干掉了!
那么接下來我都給他加上不等於試試:
explain select * from book where authoid ! = 1 and typeid ! = 2;
執行結果:
這里我就不再過多闡述了,很顯然,全部失效了;
今日感悟:
年輕人:“我有很多好的想法”
智者:“想和做,是兩種截然不同的境界,不要把自己“想做”一件事情誤會成自己“在做”一件事情”
智者:“另外,不要把“在做”一件事,誤會成“做成”一件事”