索引失效
索引是数据库中提高查询性能必不可少的一环,当SQL语句中使用不当时会导致索引失效,现在把知道的导致索引失效的原因记录下来。
不使用索引
表中建立了索引,但是完全不会使用索引的情况
当没有查询条件时,是获取全表的数据,因此是直接走的全表扫描
1
select * from test
提示不使用索引,当SQL语句中明确指定不使用某个列上的索引的话,数据库也是不会使用该索引的,idx_col指代某个建立了索引的索引列
1
select * from test ignore index(idx_col)
查询条件没有建立索引
查询条件没有使用到索引列
索引失效
表中建立了索引,查询条件中也有索引列,但是索引依然失效的几种情况
(重要)数据库引擎cost成本分析走索引的成本更高,认为全表扫描好过使用索引,可能出现的场景:表的数据量过少、索引建立不合理导致通过索引查询出来的数据太多
索引列上做操作
索引列进行了数学运算
1
select * from test where id + 1 = 1997
索引列使用了函数
1
select * from test where name = upper(name)
查询条件中,索引列的类型和传入的参数类型不一致,需要类型转换,例如:索引列id类型是int,但传入的参数类型是char;字符串条件没有使用引号
1
2select * from test where id = '1';
select * from test where name = 999;复合索引未符合最左匹配原则,例如:符合索引由A、B、C三个列组成,但查询时where条件中没有A列的条件
1
select * from test where b = param_b and c = param_c
索引列中的模糊搜索like以通配符*%*开头,类似于查字典中按偏旁查找但是不记得第一个偏旁一样,是无从下手找不到的
1
select * from test where name like '%abc'
相反如果是以通配符*%*结尾是会走索引的
1
select * from test where name like 'abc%'
使用了不等于(!=、<>),MySQL中使用不等于(!=、<>)时无法使用索引,但覆盖索引除外
1
2select * from test where age != 20;
select * from test where age <> 20;IS NULL、IS NOT NULL条件
IS NULL、IS NOT NULL都是可以走索引的,主要和数据库引擎分析得出的成本有关,成本低就走,成本高就不走。
注:MySQL中的二级索引是会记录空值的,空值放在B+树的最左侧,
查询条件中包含or(尽量少用)
or左右两则的索引列相同(命中同一个索引列),在较早期的版本是不走索引的,但是在新的版本(8.0)是走索引的(索引合并)
1
select * from test where id = 199 or id = 200
or左右两则的索引列不相同或者有一则不是索引列,是不会走索引的
1
2select * from test where key1 = 199 or key2 = 'demo';
select * from test where key1 = 199 or col = 'demo'
IN条件
在MySQL4.0以下是不走索引的,在4.1版本以上才走索引,但是如果IN后面跟的条件太多可能会不走索引,用的时候最后看一下执行计划
1
2select * from test where id in ('1', '2'); #走索引
select * from test where id in ('1', '2', '3'......); #条件太多可能不走索引NOT IN条件
查询提条件中包含NOT IN是不会走索引的,可以这样理解:不知道一条数据是不是NOT IN条件,只能查出来再判断,因此是不走索引的。
总结
MySQL下索引失效的情况比较复杂,特别是查询条件中的or、in、not in、exists、not exists,因此用explain看一下执行计划比较稳当。上面写的可能也不是全对的,后面再深入了解一下,回头再完善。