目录
一、准备工作,准备sql
二、索引是什么、使用explain关键字来解析sql使用索引情况
三、索引的使用与失效场景
1.使用全部复合索引(索引正常使用)
2.最佳左前缀法则
3.在索引列上做任何操作(计算、函数、自动或手动类型转换),会导致索引失效而转向全表扫描。
4.不能使用索引中范围条件右边的列。(范围条件之后的索引全失效,但是范围条件之前的和范围条件的还是用到索引的。)
5.尽量使用覆合索引(只访问索引的查询(索引列和查询列一致)),减少select *。
6.mysql在使用不等于(!= 或者 <>)的时候无法使用索引会导致全表扫描。(8.0似乎优化了,不等于是范围了,待验证)
7.is null、is not null也无法使用索引(这里不知道为什么is null还是走了索引。。有明白的小伙伴可以解释一下)。
8.like以通配符开头('%abc...')会导致索引失效。
9.少用or,用它来连接时会索引失效。
四、总结
这里我使用的mysql版本是 5.5.40。
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20),
`age` int(11),
`address` varchar(25),
`crtdate` timestamp,
PRIMARY KEY (`id`) USING BTREE
);
insert into student(name,age,address,crtdate) values('张三', 15, '山东青岛', now());
insert into student(name,age,address,crtdate) values('李四', 17, '山东济南', now());
insert into student(name,age,address,crtdate) values('王五', 18, '山东潍坊', now());
-- 创建复合索引
alter table student add index idx_stu_nameAgeAddr(name,age,address);
explain如何使用,请阅读这篇文章:
MySQL高级-索引是个什么东西?explain到底怎么用-MySQL查询优化大全
之前创建了name、age、address三个字段的复合索引,查询条件根据这三个字段,是可以直接使用索引的。
-- sql贴在这里了
explain select * from student where name='张三' and age=15 and address = '山东青岛';
如果索引了多列,要遵循最左前缀法则。指的是查询从索引的最左前列开始并且不跳过索引中的列。
-- sql贴在这里了
explain select * from student where name='张三' and age=15;
explain select * from student where name='张三';
explain select * from student where age=15 and address = '山东青岛';
explain select * from student where name='张三' and address = '山东青岛';
以下这两种查询都是没问题的,因为遵守最佳左前缀法则,条件字段从左到右,从第一个索引字段name开始并且也不跳过索引中间的列:
以下会造成索引完全失效,因为没有使用复合索引的第一列name:
以下会造成索引部分失效,第一个条件name是走索引的,但是address因为跳过了age所以address这个字段索引失效:
-- sql贴这里了
explain select * from student where left(name,1)='张';
索引列上使用了表达式,如where substr(name, 1, 3)='张小四'、where num = num +1,表达式是一大忌讳,再简单的表达式mysql也会造成索引失效。
有时数据量不是大到严重影响速度时,一般可以先查出来,比如先查询所有订单记录的数据,再在程序中筛选。
字符串不加单引号索引失效:(做了隐式的类型转换)
-- sql贴这里了
explain select * from student where name='张三';
explain select * from student where name='张三' and age=15;
explain select * from student where name='张三' and age=15 and address = '山东青岛';
explain select * from student where name='张三' and age>15 and address = '山东青岛';
很显然,最后一条sql,只有name、age走了索引,但是address失效了。
我们都知道,Extra中出现using index是好现象,对查询效率会增强。
而且有范围查询时,不用*的时候,key_len会更小,这意味着会增加查询效率。
-- sql贴这里了
explain select * from student where name='张三';
explain select * from student where name!='张三';
explain select * from student where name<>'张三';
-- sql贴这里了
explain select * from student where name='张三';
explain select * from student where name is null;
explain select * from student where name is not null;
like以通配符开头会导致索引失效,但是通配符放在后面索引就会正常使用。
-- sql在这里
explain select * from student where name='张三';
explain select * from student where name like '%张';
explain select * from student where name like '张%';
explain select * from student where name like '%张%';
但是,这种情况like前面使用通配符,也是会走索引的:(select查询的字段刚好是复合索引的字段,所以为什么在查询的时候不建议使用*)
explain select * from student where name='张三' or age=15;