索引优化

素材:student表
这里写图片描述
列信息:
这里写图片描述

一、复合索引按索引中的字段顺序进行检索数据

复合索引可以由好几个字段组成,在查询语句中若想使用该索引,必须按建索引字段的先后顺序使用。例如在student_num,name,age上建立一个复合索引

create index id_num_name_age on student(student_num, name, age);

例1:查询name=‘lzj’,age=27的记录
这里写图片描述
从explain分析中可以看到,type=ALL,表示全表进行的扫描;possible_keys和key都是NULL,表示没有使用索引。建立的复合索引是student_num、name、age,但是本例中只使用了name、age,略过了student_num,则不能正常使用该索引。
结论:复合索引从第一个字段开始,如果没有第一个字段,则不能正常使用复合索引。

例2:查询student_num=1, age=27的记录
这里写图片描述
从explain分析中可知,type=ref,表示非唯一索引检索;key=id_num_name_age,表示使用到了该复合索引;key_len=5,表示使用的索引长度为5,student_num是int类型,4个字节,null占一个字节,因此只使用了复合索引中的第一个字段student_num;ref=const表示student_num上用的一个常量1进行检索。本例中使用了student_num、age进行检索,实际上只使用了复合索引id_num_name_age的中的第一个索引student_num。
结论:对于使用复合索引时,一旦不能按建复合索引时字段的顺序进行使用,则连续中断的地方后面的索引无效,只使用了中断前面的索引。

二、不要在索引上做任何操作,否则导致索引失效,进而全表扫描

在用建立索引的字段进行查询时,不要在字段上进行计算、或调用mysql内置函数等,否则索引失效。
例如:查询student_num=1,name的前两个字符为’lz’的记录
这里写图片描述
从explain的分析中可以看出,key_len=5,表示只只使用了student_num字段上的索引;ref中只有一个const,表示student_num使用了常量1。因此只有studnet_num字段上的索引生效了。
结论:不要在索引字段上进行任何操作。

三、建立复合索引的几个列中,若中间的一个列是范围,则该列后面的列上的索引无效(该列是有效的)

删除前面已经建立的索引

drop index id_num_name_age on student;

然后建立新的索引

create index id_num_name_age_class on student(student_num, name, age, class);

下面查询student_num=1 and name=’lzj’ and age>20 and class=1条件下的记录
这里写图片描述
从explain分析中可以看出,type=range,表示索引检索的时范围;key_len=41,表示用到了student_num、name和age上的索引,studnet_num占用了5个字节,name时char(10)类型的并且默认为NULL,mysql中默认utf-8存储的,一个utf-8字符占3个字节,所以name=’lzj’占3*10个字节,另外一个NULL占一个字节,age占5个字节,共41个字节。因此上述条件中只用到了student_num、name、age上索引,age后面的class上的索引失效。

四、尽量使用覆盖索引

覆盖索引就是索引列与查询列一致,开发中应少使用select * 之类的。
继续使用上面的id_num_name_age_class索引
例1:查询student_num=1 and name=’lzj’ and age=27 and class=1的记录
这里写图片描述
例2:同样查询student_num=1 and name=’lzj’ and age=27 and class=1的记录,只查索引列
这里写图片描述
例2中用同样的条件去查询,但是只select索引类student_num、name、age、class列,在Extran中出现了Using index,使用了覆盖索引,查询时只需要从索引中查询需要的数据,不需要再去扫描表了,因此效率会更快。一般的查询会先从索引中找到记录,然后根据索引中记录去表中查找相应记录,因此效率不如覆盖索引高。

select student_num, name, age, class from student where student_num=1 and name='lzj';
select name from student where student_num=1 and name='lzj' and age=27 and class=1;

上面两条SQL都使用了覆盖索引,只要where条件中用到了索引,并且select中只查索引列,就会使用覆盖索引。覆盖索引是推荐使用的。

五、索引中使用 “!=” 或者 “<>”会导致索引失效

删除id_num_name_age_class索引,在name字段上建立id_name索引。

查询name=’lzj’的记录
这里写图片描述

查询name != ‘lzj’的记录
这里写图片描述
通过explain分析,key=NULL,没有使用上索引id_name,因此使用“!=”导致了索引失效,进而全表扫描。

六、is null, is not null导致索引失效

继续使用id_name索引。
例1: name列默认为NULL情况
这里写图片描述
在name列默认为空的前提下,查询name is null的情况下使用到了索引;查询name is not null 的情况下没有使用索引。

例2:name列默认为 NOT NULL的情况
修改name列的属性

alter table student modify column name char(10) NOT NULL;

这里写图片描述
当name列NOT NULL的情况下,此时查询name is null和name is not null时都没有使用上name列上的索引id_name。

七、like通配符导致索引失效

继续使用id_name索引。
这里写图片描述
通过explain分析,发现用like进行匹配时,只有首字母’lz%’不需要匹配的情况才使用上了索引,其它两种情况都没有使用上索引。

如果一定要用like形式,解决索引失效的情况,可以使用覆盖索引
这里写图片描述
从explain分析中可知,使用覆盖索引时使用到了id_name索引。也可以用主键索引进行查询,也可避免like索引失效的情况。

八、字符串不加单引号导致索引失效

继续使用id_name索引。
在student表中插入一条数据

insert into stuent values(8, 4, '110', 100, 1);

这里写图片描述
从explain分析中可见,name=110,字符串没有使用单引号,误认为是整形(但在使用时,mysql会自动转型为字符类型),导致索引失效。

九、慎用or,导致索引失效

继续使用id_name索引。
查询name=’lzj’ 或者name=’Bob’的记录
这里写图片描述
从explain分析可见,key=NULL,并没有使用上索引。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值