先来思考一个小问题。
问题:当查询条件为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;