索引在什麼情況下不會被使用?

2020-07-16 10:05:30
索引可以提高查詢的速度,但並不是使用帶有索引的欄位查詢時,索引都會起作用。使用索引有幾種特殊情況,在這些情況下,有可能使用帶有索引的欄位查詢時,索引並沒有起作用,下面重點介紹這幾種特殊情況。

1. 查詢語句中使用LIKE關鍵字

在查詢語句中使用 LIKE 關鍵字進行查詢時,如果匹配字串的第一個字元為“%”,索引不會被使用。如果“%”不是在第一個位置,索引就會被使用。

例 1

為了便於理解,我們先查詢 tb_student 表中的資料,SQL 語句和執行結果如下:
mysql> SELECT * FROM tb_student;
+----+------+------+------+
| id | name | age  | sex  |
+----+------+------+------+
|  1 | 張三 |   12 | 男   |
|  2 | 李四 |   12 | 男   |
|  3 | 王五 |   13 | 女   |
|  4 | 張四 |   13 | 女   |
|  5 | 王四 |   15 | 男   |
|  6 | 趙六 |   12 | 女   |
+----+------+------+------+
6 rows in set (0.03 sec)
下面在查詢語句中使用 LIKE 關鍵字,且匹配的字串中含有“%”符號,使用 EXPLAIN 分析查詢情況,SQL 語句和執行結果如下:
mysql>  EXPLAIN SELECT * FROM tb_student WHERE name LIKE '%四'G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tb_student
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 6
     filtered: 16.67
        Extra: Using where
1 row in set, 1 warning (0.01 sec)

mysql> CREATE INDEX index_name ON tb_student(name);
Query OK, 6 rows affected (0.13 sec)

mysql>  EXPLAIN SELECT * FROM tb_student WHERE name LIKE '李%'G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tb_student
   partitions: NULL
         type: range
possible_keys: index_name
          key: index_name
      key_len: 77
          ref: NULL
         rows: 1
     filtered: 100.00
        Extra: Using index condition
1 row in set, 1 warning (0.00 sec)
第一個查詢語句執行後,rows 引數的值為 6,表示這次查詢過程中查詢了 6 條記錄;第二個查詢語句執行後,rows 引數的值為 1,表示這次查詢過程只查詢 1 條記錄。同樣是使用 name 欄位進行查詢,因為第一個查詢語句的 LIKE 關鍵字後的字串是以“%”開頭的,所以第一個查詢語句沒有使用索引,而第二個查詢語句使用了索引 index_name。

2. 查詢語句中使用多列索引

多列索引是在表的多個欄位上建立一個索引,只有查詢條件中使用了這些欄位中的第一個欄位,索引才會被使用

例 2

在 name 和 age 兩個欄位上建立多列索引,並驗證多列索引的使用情況,SQL 語句和執行結果如下:
mysql> CREATE INDEX index_name_age ON tb_student(name,age);
Query OK, 6 rows affected (0.11 sec)

mysql> EXPLAIN SELECT * FROM tb_student WHERE name LIKE '李%'G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tb_student
   partitions: NULL
         type: range
possible_keys: index_name_age
          key: index_name_age
      key_len: 77
          ref: NULL
         rows: 1
     filtered: 100.00
        Extra: Using index condition
1 row in set, 1 warning (0.05 sec)

mysql> EXPLAIN SELECT * FROM tb_student WHERE age LIKE '12'G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tb_student
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 6
     filtered: 16.67
        Extra: Using where
1 row in set, 1 warning (0.00 sec)
第一條查詢語句的查詢條件使用了 name 欄位,分析結果顯示 rows 引數的值為 1,且查詢過程中使用了 index_name_age 索引。第二條查詢語句的查詢條件使用了 age 欄位,結果顯示 rows 引數的值為 6,且 key 引數的值為 NULL,這說明第二個查詢語句沒有使用索引。

因為 name 欄位是多列索引的第一個欄位,所以只有查詢條件中使用了 name 欄位才會使 index_name_age 索引起作用。

3. 查詢語句中使用OR關鍵字

查詢語句只有 OR 關鍵字時,如果 OR 前後的兩個條件的列都是索引,那麼查詢中將使用索引。如果 OR 前後有一個條件的列不是索引,那麼查詢中將不使用索引。

例 3

下面演示 OR 關鍵字的使用。
mysql> EXPLAIN SELECT * FROM tb_student WHERE name='張三' or sex='男'G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tb_student
   partitions: NULL
         type: ALL
possible_keys: index_name,index_name_age
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 6
     filtered: 30.56
        Extra: Using where
1 row in set, 1 warning (0.06 sec)
mysql> EXPLAIN SELECT * FROM tb_student WHERE name='張三' or id='12'G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tb_student
   partitions: NULL
         type: index_merge
possible_keys: PRIMARY,index_name,index_name_age
          key: index_name,PRIMARY
      key_len: 77,4
          ref: NULL
         rows: 2
     filtered: 100.00
        Extra: Using union(index_name,PRIMARY); Using where
1 row in set, 1 warning (0.01 sec)
由於 sex 欄位沒有索引,所以第一條查詢語句沒有使用索引;name 欄位和 id 欄位都有索引,所以第二條查詢語句使用了 index_name 和 PRIMARY 索引 。

總結

使用索引查詢記錄時,一定要注意索引的使用情況。例如,LIKE 關鍵字設定的字串不能以“%”開頭;使用多列索引時,查詢條件必須要使用這個索引的第一個欄位;使用 OR 關鍵字時,OR 關鍵字連線的所有條件都必須使用索引。