MySQL索引失效问题总结

先来思考一个小问题。

问题:当查询条件为2个及2个以上时,是创建多个单列索引还是创建一个联合索引好呢?它们之间的区别是什么?哪个效率高呢?

先来建立一些单列索引进行测试:

这里建立了一张表,里面建立了三个单列索引userId,mobile,billMonth。

然后进行多列查询。

explain select * from `t_mobilesms_11` where userid = '1' and mobile = '13504679876' and billMonth = '1998-03'

我们发现查询时只用到了userid这一个单列索引,这是为什么呢?因为这取决于MySQL优化器的优化策略。

当多条件联合查询时,优化器会评估哪个条件的索引效率高,它会选择最佳的索引去使用。也就是说,此处三个索引列都可能被用到,只不过优化器判断只需要使用userid这一个索引就能完成本次查询,故最终explain展示的key为userid。

4.1 总结

多个单列索引在多条件查询时优化器会选择最优索引策略,可能只用一个索引,也可能将多个索引都用上。

但是多个单列索引底层会建立多个B+索引树,比较占用空间,也会浪费搜索效率
所以多条件联合查询时最好建联合索引。

那联合索引就可以三个条件都用到了吗?会出现索引失效的问题吗?

4.2 联合索引失效问题

一张图搞懂MySQL的索引失效

1)违反最左匹配原则

最左匹配原则:最左优先,以最左边的为起点任何连续的索引都能匹配上,如不连续,则匹配不上。

如:建立索引为(a,b)的联合索引,那么只查 where b = 2 则不生效。换句话说:如果建立的索引是(a,b,c),也只有(a),(a,b),(a,b,c)三种查询可以生效。

这里跳过了最左的name字段进行查询,发现索引失效了。

遇到范围查询(>、<、between、like)就会停止匹配。

比如:a= 1 and b = 2 and c>3 and d =4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,因为c字段是一个范围查询,它之后的字段会停止匹配。

2)在索引列上做任何操作

如计算、函数、(手动或自动)类型转换等操作,会导致索引失效而进行全表扫描。

explain select * from user where left(name,3) = 'zhangsan' and age =20

这里对name字段进行了left函数操作,导致索引失效。

3)使用不等于(!= 、<>)

explain select * from user where age != 20;
explain select * from user where age <> 20;

4)like中以通配符开头('%abc')

索引失效

explain select * from user where name like ‘%zhangsan’;

索引生效

explain select * from user where name like ‘zhangsan%’;

5)字符串不加单引号索引失效

explain select * from user where name = 2000;

6)or连接索引失效

explain select * from user where name = ‘2000’ or age = 20 or pos =‘cxy’;

7)order by

正常(索引参与了排序),没有违反最左匹配原则。

explain select * from user where name = 'zhangsan' and age = 20 order by age,pos;

违反最左前缀法则,导致额外的文件排序(会降低性能)。

explain select name,age from user where name = 'zhangsan' order by pos;

8)group by

正常(索引参与了排序)。

explain select name,age from user where name = 'zhangsan' group by age;

违反最左前缀法则,导致产生临时表(会降低性能)。

explain select name,age from user where name = 'zhangsan' group by pos,age;
原文地址:https://www.cnblogs.com/aitree/p/14465231.html