MySQL 索引失效-模糊查詢,最左匹配原則,OR條件等。( 四 )


select * from t_user where id = CAST("1" AS signed int);可以看到,索引字段并沒有用任何函數,CAST 函數是用在了輸入參數 , 因此是可以走索引掃描的 。
聯合索引非最左匹配對主鍵字段建立的索引叫做聚簇索引,對普通字段建立的索引叫做二級索引 。
那么多個普通字段組合在一起創建的索引就叫做聯合索引,也叫組合索引 。
創建聯合索引時,我們需要注意創建時的順序問題,因為聯合索引 (x, y, z) 和 (z, y, x) 在使用的時候會存在差別 。
聯合索引要能正確使用需要遵循最左匹配原則,也就是按照最左優先的方式進行索引的匹配 。
比如,如果創建了一個 (a, b, c) 聯合索引,如果查詢條件是以下這幾種,就可以匹配上聯合索引:

  • where a=1;
  • where a=1 and b=2 and c=3;
  • where a=1 and b=2;
需要注意的是,因為有查詢優化器 , 所以 x 字段在 where 子句的順序并不重要 。
但是,如果查詢條件是以下這幾種,因為不符合最左匹配原則,所以就無法匹配上聯合索引,聯合索引就會失效:
  • where b=2;
  • where c=3;
  • where b=2 and c=3;
有一個比較特殊的查詢條件:where a = 1 and c = 3 ,符合最左匹配嗎?
這種其實嚴格意義上來說是屬于索引截斷,不同版本處理方式也不一樣 。
MySQL 5.5 的話,前面 a 會走索引 , 在聯合索引找到主鍵值后,開始回表,到主鍵索引讀取數據行,然后再比對 z 字段的值 。
從 MySQL5.6 之后,有一個索引下推功能 , 可以在索引遍歷過程中,對索引中包含的字段先做判斷,直接過濾掉不滿足條件的記錄 , 減少回表次數 。
大概原理是:截斷的字段會被下推到存儲引擎層進行條件判斷(因為 c 字段的值是在 (a, b, c) 聯合索引里的),然后過濾出符合條件的數據后再返回給 Server 層 。由于在引擎層就過濾掉大量的數據,無需再回表讀取數據來進行判斷,減少回表次數 , 從而提升了性能 。
比如下面這條 where a = 1 and c = 0 語句,我們可以從執行計劃中的 Extra=Using index condition 使用了索引下推功能 。
MySQL 索引失效-模糊查詢,最左匹配原則,OR條件等。

文章插圖
為什么聯合索引不遵循最左匹配原則就會失效?
原因是,在聯合索引的情況下,數據是按照索引第一列排序,第一列數據相同時才會按照第二列排序 。
也就是說 , 如果我們想使用聯合索引中盡可能多的列,查詢條件中的各個列必須是聯合索引中從最左邊開始連續的列 。如果我們僅僅按照第二列搜索,肯定無法走索引 。
WHERE 子句中的 OR在 WHERE 子句中,如果在 OR 前的條件列是索引列,而在 OR 后的條件列不是索引列,那么索引會失效 。
舉個例子,比如下面的查詢語句,id 是主鍵,age 是普通列,從執行計劃的結果看,是走了全表掃描 。
select * from t_user where id = 1 or age = 18;
MySQL 索引失效-模糊查詢,最左匹配原則,OR條件等。

文章插圖
這是因為 OR 的含義就是兩個只要滿足一個即可 , 因此只有一個條件列是索引列是沒有意義的 , 只要有條件列不是索引列,就會進行全表掃描 。
要解決辦法很簡單,將 age 字段設置為索引即可 。
MySQL 索引失效-模糊查詢,最左匹配原則,OR條件等。

文章插圖
可以看到 type=index merge ,  index merge 的意思就是對 id 和 age 分別進行了掃描,然后將這兩個結果集進行了合并,這樣做的好處就是避免了全表掃描 。
總結今天給大家介紹了 6 種會發生索引失效的情況: