索引可以提高查询速度,但并不是每个带有索引的查询都使用到了索引,存在特殊情况下索引没有被使用的情况。本节将详细介绍3种索引没有被使用的特殊情况。
一、使用LIKE查询:
使用 LIKE 关键字进行查询时,如果匹配字符串的第一个字符为“%”,索引不会被使用。
举个例子:
我们可以先查询一张表,这里查询dotcpp_user表:
为了进行对比,我们先为hobby字段创建索引:
CREATE INDEX index_hobby ON dotcpp_user(hobby);
然后我们再查询一次,这次查询使用LIKE并且查询第一个字符是'%',同时使用EXPLAIN解释该语句:
EXPLAIN SELECT * FROM dotcpp_user WHERE hobby LIKE '%高精度' \G
结果:
*************************** 1. row *************************** id: 1 select_type: SIMPLE table: dotcpp_user partitions: NULL type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 28 filtered: 11.11 Extra: Using where 1 row in set, 1 warning (0.00 sec)
虽然hobby有索引,但是由于没有利用索引,查询必然触发全表扫描,预估需要扫描 28 行记录。
随即进行对比查询:
EXPLAIN SELECT * FROM dotcpp_user WHERE hobby LIKE '高精度%'\G
结果:
*************************** 1. row *************************** id: 1 select_type: SIMPLE table: dotcpp_user partitions: NULL type: range possible_keys: index_hobby key: index_hobby key_len: 103 ref: NULL rows: 2 filtered: 100.00 Extra: Using index condition 1 row in set, 1 warning (0.00 sec)
此时hobby字段利用索引,查询效率大大提高,预估需要扫描 2 行记录,有力证明了 LIKE 关键字进行查询时,如果匹配字符串的第一个字符为“%”,索引不会被使用!
二、查询语句中使用多列索引:
多列索引(也称为复合索引)指的是在表的多个字段创建索引,遵循“最左前缀匹配原则”(Leftmost Prefix Principle),即:只有查询条件中使用了这些字段中的第一个字段,索引才会被使用!
举个例子:
现在我们为name字段和hobby字段创建多列索引并通过实例说明“最左前缀匹配原则”:
CREATE INDEX index_name_hobby ON dotcpp_user(name,hobby);
我们查询并解释name字段的'dotcppUser03';
EXPLAIN SELECT * FROM dotcpp_user WHERE name like 'dotcppUser03' \G
发现有效利用索引,预估只需要扫描1 行索引记录就能找到结果。
此时如果我们跳过name字段,直接查询hobby字段呢?
EXPLAIN SELECT * FROM dotcpp_user WHERE hobby = '高精度' \G
mysql> EXPLAIN SELECT * FROM dotcpp_user WHERE hobby = '高精度' \G
*************************** 1. row *************************** id: 1 select_type: SIMPLE table: dotcpp_user partitions: NULL type: index possible_keys: index_name_hobby key: index_name_hobby key_len: 206 ref: NULL rows: 28 filtered: 10.00 Extra: Using where; Using index 1 row in set, 1 warning (0.00 sec)
key: index_name_hobby,说明优化使用了索引,但是没有利用索引,预估只需要扫描28行索引记录就能找到结果。
三、查询语句中使用OR关键字:
这个就比较容易理解了,我们先保证id字段和hobby字段有索引,name字段没有索引:
EXPLAIN SELECT * FROM dotcpp_user WHERE id=3 OR hobby='汉诺塔' \G
*************************** 1. row *************************** id: 1 select_type: SIMPLE table: dotcpp_user partitions: NULL type: index_merge possible_keys: PRIMARY,index_hobby key: PRIMARY,index_hobby key_len: 4,103 ref: NULL rows: 3 filtered: 100.00 Extra: Using union(PRIMARY,index_hobby); Using where 1 row in set, 1 warning (0.00 sec)
使用了主键、index_hobby查询,预计3行记录出结果:
如果我们查询一个不带索引的字段呢?
EXPLAIN SELECT* FROM dotcpp_user WHERE id= 5 OR name = 'dotcppUser03' \G
*************************** 1. row *************************** id: 1 select_type: SIMPLE table: dotcpp_user partitions: NULL type: ALL possible_keys: PRIMARY key: NULL key_len: NULL ref: NULL rows: 28 filtered: 13.60 Extra: Using where 1 row in set, 1 warning (0.00 sec)
看到type ; ALL那就没事了,全表扫描,虽然你id有主键索引,但是你name无索引,那就老老实实全表扫描吧。使用关键字OR,如果有一个字段没有使用索引,那么查找无法使用索引!
结论:通过索引查询,LIKE查询的字符串首字符是'%'会导致索引没有被使用,多列索引没有遵循“最左前缀匹配原则”会导致索引没有被使用,OR关键字连接的字段如果有一个字段没有索引那么也会导致索引没有被使用。
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程