什么情况下索引会失效?

前提条件:
sms表索引:

index_smsId:`smsId`
index_mobile_createdAt:`mobile`, `createdAt`
index_status:`status`

whiteList表无索引字段

一、like 以%开头:

explain select * from sms WHERE smsId LIKE '%1';
不生效.png

如果只查询带索引字段的列,可以命中:

explain select smsId from sms WHERE smsId LIKE '%1';
生效.png

二、or语句前后没有同时使用索引:

当or左右查询字段只有一个是索引,该索引失效,只有当or左右查询字段均为索引时,才会生效:

explain select * from sms WHERE smsId = '1' or channel = 1;
不生效.png

explain select * from sms WHERE smsId = '1' or mobile='138xxxxxxxx';
生效.png

三、组合索引,不是使用第一列索引,索引失效:

explain select * from sms WHERE createdAt > '2021-03-13 15:05:38';
组合索引.png

四、对查询的列上有运算或者函数的:

explain SELECT * FROM sms where substr(smsId,-2)='12';
函数.png

explain select smsId from sms WHERE status+1 = 3;
运算.png

五、数据类型出现隐式转化:

这其实是四的一种特殊情况,如varchar不加引号的话可能会自动转换为int型,使索引无效:

explain select * from sms WHERE mobile=138xxxxxxxx
类型转化.png

mysql有个类型转换规则就是将“字符转成数字”,所以以上sql就等价于这样:

explain select * from sms WHERE cast(mobile as signed)= 138xxxxxxxx

六、连接查询中,按照优化器顺序的第一张表不会走索引:

explain select * from sms a left join whiteList b on a.smsId = b.mobile

此时a表sms上的smsId是有索引的,b表mobile无索引
无效.png
//相当于执行以下循环
List> resultA=select * from sms a
for(Map map: resultA){
       List> resultB=select * from whiteList b where b.mobile=map.get("smsId")
}

现在将表的连接位置互换:

explain select * from whiteList b left join sms a on a.smsId = b.mobile;
有效.png
//相当于执行以下循环
List> resultA=select * from whiteList b
for(Map map: resultA){
       List> resultB=select * from sms a where a.smsId=map.get("mobile")
}

改为右连:
explain select * from sms a right join whiteList b on a.smsId = b.mobile;


有效.png
//相当于执行以下循环
List> resultA=select * from whiteList b
for(Map map: resultA){
       List> resultB=select * from sms a where a.smsId=map.get("mobile")
}

从上面连接查询来看左外连接a表没有用到索引,这就是因为由于是左外连接,所以优化器的执行顺序是a表、b表,也就是说首先全表扫描a表,再根据a表的smsId值查询b表的值,所以a表无法用到索引。

七、在索引字段上使用not,<>,!=

八、如果mysql估计使用全表扫描要比使用索引快,则不使用索引

参考:
https://www.jianshu.com/p/3ccca0444432
https://www.cnblogs.com/wdss/p/11186411.html

你可能感兴趣的:(什么情况下索引会失效?)