開門見山
如果MySQL無法根據當前條件找出唯一的一條下潛路線或者索引有序性被破壞,此時索引失效(停止索引)
唯一的意思是僅有一條;找不到和找到好幾個都不屬於唯一
例子
常見的六種失效
MySQL索引以B+樹為基礎,在建立表時,InnoDB 儲存引擎預設會建立一個主鍵索引,也就是聚簇索引,其它索引都屬於二級索引。其中主鍵索引存放了資料,二級索引存放了主鍵,使用二級索引會產生回表操作
對索引使用左或者左右模糊匹配
對索引使用左模糊好理解
select * from t_user where name like '%林';
MySQL的字串比較是從左往右以此比較的,使用左模糊就意味著,只要是個以林為字尾的字串就符合要求小林
,1林
,2林
等等;
而從B+樹的角度看,這些字串可能分佈在樹的各個位置,被查詢資料是無序的,B+樹完全無法找到唯一的下潛路徑,不如直接全表掃描
對索引使用右模糊好
select * from t_user where name like '林%';
由上面可知,索引可以找到唯一的一條下潛路徑,直到最終定位到一個子樹上,這個子樹的name都是以林
開頭的;這時索引結束,直接移動到子節點上,轉為range
。
對索引使用函式
select * from t_user where length(name)=6;
我們的索引是以name
的值為基礎建立的,在name
層面是有序的,但在length(name)
無法保證有序性,當前節點的左側和右側都有可能存在長度為6的字串,MySQL無法根據當前條件找出唯一的一條下潛路線
比如你站在h點,你會發現往左往右都對
被函式處理的數值,無法保證其有序性和原始數值相同
對索引進行表示式計算
select * from t_user where id + 1 = 10;
實際上這個例子不太好,因為只是簡單的 +1 並不影響原始的有序性,路徑也是唯一的,實際上從理論上是可以用索引的;但在實際中表達式運算可能很複雜,以至於其y值可能解出多個x值;這時候x是不唯一的,MySQL無法找到唯一的下潛路徑
更合適的例子
bash程式碼解讀複製程式碼select * from t_user where id*id = 4;此時
id = 2 or -2
;此時你站在0點,你會發現往左往右都對
對索引隱式型別轉換
這一條涉及到MySQL的特性
MySQL 在遇到字串和數字比較的時候,會自動把字串轉為數字,然後再進行比較。
當索引值為字串,條件是數字時;MySQL會去轉換索引值,此時類似於對索引使用函式;有序性被破壞,MySQL無法找出唯一的一條下潛路徑
當索引值為陣列,條件是字串時,被轉換的是條件,可以繼續走索引
聯合索引非最左匹配
在聯合索引的情況下,資料是按照索引第一列排序,第一列資料相同時纔會按照第二列排序。 也就是說,如果我們想使用聯合索引中儘可能多的列,查詢條件中的各個列必須是聯合索引中從最左邊開始連續的列。如果我們僅僅按照第二列搜尋,肯定無法走索引。
這個好理解,如果我們的索引是(a, b, c)
,但查詢條件是b
or c
or b and c
;此時等同於不存在索引,MySQL當然也無法根據這些條件去找到唯一的下潛路徑
這裏還有個索引下推的知識點,當查詢條件為
a and c
時可以觸發
WHERE 對非索引列執行 or 運算
顯而易見,對非索引列執行查詢只能全表掃描;MySQL找不到索引路徑;
當然,如果兩個都是索引,MySQL可以分別索引,然後求並集;
總結
今天給大家介紹了 6 種會發生索引失效的情況:
當我們使用左或者左右模糊匹配的時候,也就是
like %xx
或者like %xx%
這兩種方式都會造成索引失效;當我們在查詢條件中對索引列使用函式,就會導致索引失效。
當我們在查詢條件中對索引列進行表示式計算,也是無法走索引的。
MySQL 在遇到字串和數字比較的時候,會自動把字串轉為數字,然後再進行比較。如果字串是索引列,而條件語句中的輸入引數是數字的話,那麼索引列會發生隱式型別轉換,由於隱式型別轉換是透過 CAST 函式實現的,等同於對索引列使用了函式,所以就會導致索引失效。
聯合索引要能正確使用需要遵循最左匹配原則,也就是按照最左優先的方式進行索引的匹配,否則就會導致索引失效。
在 WHERE 子句中,如果在 OR 前的條件列是索引列,而在 OR 後的條件列不是索引列,那麼索引會失效。
結尾見山
如果MySQL無法根據當前條件找出唯一的一條下潛路線或者索引有序性被破壞,此時索引失效(停止索引)