前提条件:
sms表索引:
index_smsId:`smsId`
index_mobile_createdAt:`mobile`, `createdAt`
index_status:`status`
whiteList表无索引字段
一、like 以%开头:
explain select * from sms WHERE smsId LIKE '%1';
如果只查询带索引字段的列,可以命中:

二、or语句前后没有同时使用索引:
当or左右查询字段只有一个是索引,该索引失效,只有当or左右查询字段均为索引时,才会生效:

explain select * from sms WHERE smsId = '1' or mobile='138xxxxxxxx';

三、组合索引,不是使用第一列索引,索引失效:
explain select * from sms WHERE createdAt > '2021-03-13 15:05:38';
四、对查询的列上有运算或者函数的:
explain SELECT * FROM sms where substr(smsId,-2)='12';
explain select smsId from sms WHERE status+1 = 3;

五、数据类型出现隐式转化:
这其实是四的一种特殊情况,如varchar不加引号的话可能会自动转换为int型,使索引无效:

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

//相当于执行以下循环
List<Map<String,Object>> resultA=select * from sms a
for(Map<String,Object> map: resultA){
List<Map<String,Object>> resultB=select * from whiteList b where b.mobile=map.get("smsId")
}
现在将表的连接位置互换:

//相当于执行以下循环
List<Map<String,Object>> resultA=select * from whiteList b
for(Map<String,Object> map: resultA){
List<Map<String,Object>> 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;

//相当于执行以下循环
List<Map<String,Object>> resultA=select * from whiteList b
for(Map<String,Object> map: resultA){
List<Map<String,Object>> 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
网友评论