前言:索引优化的目的主要是让索引不失效,本篇通过相关案例对索引优化进行讲解。


0.准备

创建经典的tb_emp表。

DROP TABLE IF EXISTS `tb_emp`;
CREATE TABLE `tb_emp` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
`age` int(11) NOT NULL,
gender varchar(10) NOT NULL,
email varchar(20),
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
INSERT INTO `tb_emp` (name,age,gender,email) VALUES ('Tom', '','male','1@qq.com');
INSERT INTO `tb_emp` (name,age,gender,email) VALUES ('Mary', '','female','2@qq.com');
INSERT INTO `tb_emp` (name,age,gender,email) VALUES ('Jack', '','male','3@qq.com');
INSERT INTO `tb_emp` (name,age,gender,email) VALUES ('Rose', '','female','4@qq.com');

注:创建了tb_emp表,并插入了4条数据。

1.最佳左前缀法则

#1.定义:在创建了多列索引的情况下,查询从索引的最左前列开始且不能跳过索引中的列。

最佳左前缀法则就是说如果创建了多个索引,在使用索引时要按照创建索引的顺序来使用,不能缺少或跳过,当然如果只使用最左边的索引列,也就是第一个索引是可以的,通俗理解:“带头大哥不能死,中间兄弟不能断”。要点:“头不能掉”。下面将用案例进行说明。

#2.创建组合索引,并执行explain。

Case 1:

分析:

①索引的创建顺序为name,age,gender;

②直接使用name(带头大哥)作为条件,可以看到type=ref,key_len=82,ref=const,效果还不错。

Case 2:

分析:

没使用带头大哥(name),直接用兄弟,type=ALL,为全表扫描。

Case 3:

分析:

①对比上面两句sql语句可发现:我们使用:火车头(name)和中间车厢(age)、火车头(name)和车尾(gender)。

②虽然type=ref,但是观察key_len和ref两项,并对比Case1中的结果,可得出在使用火车头(name)和车尾(gender)时,只使用了部分索引也就是火车头(name)的索引。

③通俗理解:火车头单独跑没问题,火车头与直接相连的车厢一起跑也没问题,但是火车头与车尾,如果中间没有车厢,只能火车头自己跑。

Case 4:

分析:

火车头加车厢加车尾,三者串联,就变成了奔跑的小火车。type=ref,key_len=128,ref=const,const,const。

最佳左前缀法则总结:带头大哥不能死,中间兄弟不能断;带头大哥可跑路,老二也可跟着跑,其余兄弟只能死

2.不要在索引列上做任何操作

在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效从而转向全表扫描。

Case 1:

分析:

这里使用了函数计算,type=ALL,导致索引失效。

Case 2:

分析:

将name=‘Tom’的值修改为‘123’,使用sql后,发生了类型转换,type=ALL,导致全表扫描。

结论:在索引列上做任何操作,都会导致索引失效转向全表扫描。

3.范围右边全失效

存储引擎不能使用索引中范围右边的列,也就是说范围右边的索引列会失效。

Case 1:

Case 2:

Case 3:

Case 4:

对以上4个case进行分析:

①条件单独使用name时,type=ref,key_len=82,ref=const。

②条件加上age时(使用常量等值),type=ref,key_len=86,ref=const,const。

③当全值匹配时,type=ref,key_len=128,ref=const,const,const。说明索引全部用上,从key_len与ref可以看出。

④当使用范围时(age>27),type=range,key_len=86,ref=Null,与Case 1、Case2和Case3可知,使用了部分索引,但gender索引没用上(与Case 3对比)。

结论:范围右边的索引列失效。

4.尽量使用覆盖索引

尽量使用覆盖索引(查询列和索引列尽量一致,通俗说就是对A、B列创建了索引,然后查询中也使用A、B列),减少select *的使用。

Case 1:

Case 2:

分析:

对比Case1和Case2,Case1使用select *,Case2使用覆盖索引(查询列与条件列对应),可看到Extra从Null变成了Using index,提高检索效率。

5.使用不等于(!=或<>)会使索引失效

结论:使用!=会使type=ALL,key=Null,导致全表扫描,并且索引失效。

6.is null 或 is not null也无法使用索引

Case 1:

Case 2:

分析:

在使用is null的时候,索引完全失效,使用is not null的时候,type=ALL全表扫描,key=Null索引失效。

这里的例子可能有点特殊,具体情况肯能和case上的有所不同,但是还是要注意is null和is not null的使用。

7.like通配符以%开头会使索引失效

Case 1:

Case 2:

Case 3:

分析:

①like的%位置不同,所产生的效果不一样,当%出现在左边的时候,type=ALL,key=Null(全表扫描,索引失效),当%出现在右边的时候,type=range,索引未失效。

②like查询为范围查询,%出现在左边,则索引失效。%出现在右边索引未失效。口诀:like百分加右边。

但是在实际生产环境中,%仅出现在右边可能不能够解决我们的问题,所以解决%出现在左边索引失效的方法:使用覆盖索引。

Case 4:

分析:对比Case1可知,通过覆盖索引type=index,并且使用了Using index,从全表扫描变成了全索引扫描,还是不错的。

Case 5:

分析:这里出现type=index,因为主键自动创建唯一索引。

Case 6:

分析:上面四组explain执行的结果都相同,表明都使用了索引,从这里可以深刻的体会到覆盖索引:完全吻合或者沾边(age),都可以使type=index。

Case 7:

分析:由于只在(name,age,gender)上创建索引,当包含email时,导致结果集偏大(email未建索引)【锅大,锅盖小,不能匹配】,所以type=ALL。

8.字符串不加单引号导致索引失效

Case 1:

分析:上述两条sql语句都能查询出相同的数据。

Case 2:

分析:

通过explain执行结果可以看出,字符串(name)不加单引号在查询的时候,导致索引失效(type=ref变成了type=ALL,并且key=Null),并全表扫描。

结论:varchar类型的字段,在查询的时候不加单引号导致索引失效,转向全表扫描。

9.少用or,用or连接会使索引失效

结论:通过上述explain的执行结果可看出,在使用or连接的时候type=ALL,key=Null,索引失效,并全表扫描。

总结

①全值匹配。

②最佳左前缀法则:带头大哥不能死,中间兄弟不能断;带头大哥可跑路,老二也可跟着跑,其余兄弟只能死

③索引列上不计算。

④覆盖索引记住用。

⑤不等于、is null、is not null导致索引失效。

⑥like百分加右边,加左边导致索引失效,解决方法:使用覆盖索引。

⑦字符串不加单引号导致索引失效。

⑧少用or,用or导致索引失效。


by Shawn Chen,2018.6.25日,上午。


相关内容

MySQL高级知识系列目录

MySQL高级知识(六)——索引优化的更多相关文章

  1. MySQL高级第二章——索引优化分析

    一.SQL性能下降原因 1.等待时间长?执行时间长? 可能原因: 查询语句写的不行 索引失效(单值索引.复合索引) CREATE INDEX index_user_name ON user(name) ...

  2. MySQL高级知识(八)——ORDER BY优化

    前言:在使用order by时,经常出现Using filesort,因此对于此类sql语句需尽力优化,使其尽量使用Using index. 0.准备 #1.创建test表. drop table i ...

  3. MySQL高级知识(七)——索引面试题分析

    前言:该篇随笔通过一些案例,对索引相关的面试题进行分析. 0.准备 #1.创建test表(测试表). drop table if exists test; create table test( id ...

  4. MySQL高级知识(五)——索引分析

    前言:前面已经学习了explain(执行计划)的相关知识,这里利用explain对索引进行优化分析. 0.准备 首先创建三张表:tb_emp(职工表).tb_dept(部门表)和tb_desc(描述表 ...

  5. MySQL高级知识(三)——索引

    前言:索引在sql调优部分占据着重要的位置,了解并深入索引对我们来说也是非常重要的.本篇主要介绍MySQL中索引的相关知识点. 1.索引是什么 MySQL官方对索引的定义:索引(Index)是帮助My ...

  6. MySQL高级知识(十六)——小表驱动大表

    前言:本来小表驱动大表的知识应该在前面就讲解的,但是由于之前并没有学习数据批量插入,因此将其放在这里.在查询的优化中永远小表驱动大表. 1.为什么要小表驱动大表呢 类似循环嵌套 for(int i=5 ...

  7. MySQL高级知识系列目录

    MySQL高级知识(一)——基础 MySQL高级知识(二)——Join查询 MySQL高级知识(三)——索引 MySQL高级知识(四)——Explain MySQL高级知识(五)——索引分析 MySQ ...

  8. MySQL高级知识(四)——Explain

    前言:explain(执行计划),使用explain关键字可以模拟优化器执行sql查询语句,从而知道MySQL是如何处理sql语句.explain主要用于分析查询语句或表结构的性能瓶颈. 注:本系列随 ...

  9. MySQL高级知识(十四)——行锁

    前言:前面学习了表锁的相关知识,本篇主要介绍行锁的相关知识.行锁偏向InnoDB存储引擎,开销大,加锁慢,会出现死锁,锁定粒度小,发生锁冲突的概率低,但并发度高. 0.准备 #1.创建相关测试表tb_ ...

随机推荐

  1. sql server查询语句条件判断字段值是否为NULL

    判断字段是否为null select * from table where c is null    select * from table where c is not null 判断字段是否为空 ...

  2. Sql Server 数据库表结构,存储过程,视图比较脚本

    顶级干货 用来比较两个数据库之间 表结构,存储过程及视图差异的存储过程,直接复制对应的存储过程,无需改动,直接在数据库中执行(传递要比较的数据库参数)即可 1.两个数据库之间存储过程及视图差异比较的存 ...

  3. Linux-cut命令(22)

    cut剪切命令cut命令通常用来对某个文本文件进行解析,擅长处理以一个字符间隔的文本内容 -b :以字节(bytes)为单位进行分割.这些字节位置将忽略多字节字符边界,除非也指定了 -n 标志. -c ...

  4. spring_05装配bean

    一.前言 <bean id="user1" scope="singleton" init-method="myInit" destro ...

  5. D. GukiZ and Binary Operations(矩阵+二进制)

    D. GukiZ and Binary Operations   We all know that GukiZ often plays with arrays. Now he is thinking ...

  6. Java反射的简单入门

    1.Class的简单介绍 Class类的类表示正在运行的Java应用程序中的类和接口. 枚举是一种类,一个注解是一种接口, 每个数组也属于一个反映为类对象的类,该对象由具有相同元素类型和维数的所有数组 ...

  7. 如何清除浮动(float)所带来的影响

    清除浮动(float) 1.定义和用法 在w3c中给了浮动这样的定义. "float 属性定义元素在哪个方向浮动.以往这个属性总应用于图像,使文本围绕在图像周围,不过在 CSS 中,任何元素 ...

  8. mac svn的使用

    一.概述 在windows下,我们常常用TortoiseSVN管理svn代码.在mac下,自带svn客户端和服务器端功能. 二.服务端:创建代码仓库,用来存储客户端所上传的代码 (1)创建svn代码存 ...

  9. 在 ELK Docker 容器中查看,删除索引

    使用 Docker 搭建好 ELK ( https://www.cnblogs.com/klvchen/p/9268510.html ) 环境后,如需查看 elasticsearch 的索引可采取以下 ...

  10. LNMP的配置与优化

    一.LNMP的下载 LNMP一键安装包是一个用Linux Shell编写的可以为CentOS/RadHat/Fedora.Debian/Ubuntu/Raspbian/Deepin VPS或独立主机安 ...