MySQL高级知识(六)——索引优化
前言:索引优化的目的主要是让索引不失效,本篇通过相关案例对索引优化进行讲解。
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高级第二章——索引优化分析
一.SQL性能下降原因 1.等待时间长?执行时间长? 可能原因: 查询语句写的不行 索引失效(单值索引.复合索引) CREATE INDEX index_user_name ON user(name) ...
- MySQL高级知识(八)——ORDER BY优化
前言:在使用order by时,经常出现Using filesort,因此对于此类sql语句需尽力优化,使其尽量使用Using index. 0.准备 #1.创建test表. drop table i ...
- MySQL高级知识(七)——索引面试题分析
前言:该篇随笔通过一些案例,对索引相关的面试题进行分析. 0.准备 #1.创建test表(测试表). drop table if exists test; create table test( id ...
- MySQL高级知识(五)——索引分析
前言:前面已经学习了explain(执行计划)的相关知识,这里利用explain对索引进行优化分析. 0.准备 首先创建三张表:tb_emp(职工表).tb_dept(部门表)和tb_desc(描述表 ...
- MySQL高级知识(三)——索引
前言:索引在sql调优部分占据着重要的位置,了解并深入索引对我们来说也是非常重要的.本篇主要介绍MySQL中索引的相关知识点. 1.索引是什么 MySQL官方对索引的定义:索引(Index)是帮助My ...
- MySQL高级知识(十六)——小表驱动大表
前言:本来小表驱动大表的知识应该在前面就讲解的,但是由于之前并没有学习数据批量插入,因此将其放在这里.在查询的优化中永远小表驱动大表. 1.为什么要小表驱动大表呢 类似循环嵌套 for(int i=5 ...
- MySQL高级知识系列目录
MySQL高级知识(一)——基础 MySQL高级知识(二)——Join查询 MySQL高级知识(三)——索引 MySQL高级知识(四)——Explain MySQL高级知识(五)——索引分析 MySQ ...
- MySQL高级知识(四)——Explain
前言:explain(执行计划),使用explain关键字可以模拟优化器执行sql查询语句,从而知道MySQL是如何处理sql语句.explain主要用于分析查询语句或表结构的性能瓶颈. 注:本系列随 ...
- MySQL高级知识(十四)——行锁
前言:前面学习了表锁的相关知识,本篇主要介绍行锁的相关知识.行锁偏向InnoDB存储引擎,开销大,加锁慢,会出现死锁,锁定粒度小,发生锁冲突的概率低,但并发度高. 0.准备 #1.创建相关测试表tb_ ...
随机推荐
- pdf.js插件使用记录,在线打开pdf
天记录一个js库:pdf.js.主要是实现在线打开pdf功能.因为项目需求需要能在线查看pdf文档,所以就研究了一下这个控件. 有些人很好奇,在线打开pdf文档浏览器不是支持吗.是的你说的都是现代浏览 ...
- springMVC_11拦截器实现登录
一. 思路 controller实现核对用户名和密码,如果核对正确则保存到session中并且跳转到主页 系统中包含诸多界面,部分界面不需要登录即可进行访问,通过拦截器实现判断是否是不需要登录的界 ...
- Java_Properties
Java_Properties类 Hashtable与HashMap区别 主要:Hashtable线程安全,同步,效率相对低下 HashMap线程不安全,异步,效率高 父类:Hashtable父类是D ...
- Maven(五)Eclipse配置Maven插件
较新版本的Eclipse内置Maven插件 1. 设置installation 一般不适用内置的 指定核心程序的位置 2. 设置user settings 指定本地仓库的位置 1.如果setting. ...
- Mybatis框架可视化(1)
Mybatis整体架构视图: 接 口 层 SqlSession (定义了Mybatis暴露给应用程序调用的API) 核 心 处 理 层 配置解析 (加载核心配置.映射配置. mapper接口注解信息, ...
- 远程过程调用概述-RMI简介
简介: RPC是远程过程调用(Remote Procedure Call)的缩写形式.SAP系统RPC调用的原理其实很简单,有一些类似于三层构架的C/S系统,第三方的客户程序通过接口调用SAP内部的标 ...
- IIS服务器被配置为不列出此目录的内容
使用 IIS 管理器启用目录浏览. 打开 IIS 管理器. 在“功能”视图中,双击“目录浏览”. 在“目录浏览”页上,在“操作”窗格中单击“启用”.
- 关于Object数组强转成Integer数组的问题:Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
一.当把Object数组,强转的具体的Integer数组时,会报错. 代码如下: //数组强转报错演示 Object[] numbers = {1,2,3}; Integer[] ints = (In ...
- 从发布订阅模式到redux(一)
最近在学习的过程中,学习了一些关于redux的一些知识,学之前用redux,虽然会用但是实现的原理就不是特别清楚,天天沉迷于搬砖 总是这木搬砖也不是个事啊,就准备开始深入了解一些原理性的东西 首先在看 ...
- vue.js及项目实战[笔记]— 03 vue.js插件
一. vue补充 1. 获取DOM元素 救命稻草,document.querySelector 在template中标示元素`ref = "xxx" 在要获取的时候,this.$r ...