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_ ...
随机推荐
- C# 插入条码到Excel指定单元格
.NET中Barcode Library的应用二 介绍 在上一篇中我已经简单介绍了这个函数库(条形码应用之一------------函数库的简介).在这一篇中我将使用这个库提供更多的操作,希望对大家有 ...
- 易宝支付Demo,生产中封装成简洁的代付接口,不用request如何获取项目运行时的真实路径
最近项目在做融360引流,涉及到了易宝支付的代扣和代付.易宝官方给出的demo只能简单运行,而且都是通过form表单的形式提交,返回XML格式.同时接口代码都写在了JSP中看起来不友好.项目在生成中想 ...
- Spring Security Oauth2 示例
所有示例的依赖如下(均是SpringBoot项目) pom.xml <dependencies> <dependency> <groupId>org.springf ...
- Python3 系列之 面向对象篇
面向对象的三大特性:继承.封装和多态 Python 做到胶水语言,当然也支持面向对象的编程模式. 封装 class UserInfo(object): lv = 5 def __init__(self ...
- for循环与forEach性能思考
今日看到一句话: 基于循环的迭代比基于函数的迭代法快8倍,因此有了该篇验证博客. 验证代码如图: 验证结果:在数量比较少的时候,无明显差别,当数量级达到10的4次方时候,for循环的效率优势明显:如图 ...
- 二进制安装 kubernetes 1.12(三) - 部署 Master 节点组件
在Master节点部署组件 在部署Kubernetes之前一定要确保etcd.flannel.docker是正常工作的,否则先解决问题再继续. 创建 CA 证书 mkdir -p /iba/master ...
- K8S 部署 ingress-nginx (一) 原理及搭建
Kubernetes 暴露服务的有三种方式,分别为 LoadBlancer Service.NodePort Service.Ingress.官网对 Ingress 的定义为管理对外服务到集群内服务之 ...
- JS中的反柯里化( uncurrying)
反柯里化 相反,反柯里化的作用在与扩大函数的适用性,使本来作为特定对象所拥有的功能的函数可以被任意对象所用.即把如下给定的函数签名, obj.func(arg1, arg2) 转化成一个函数形式,签名 ...
- listview reclyerview上下拉刷新
x写控件挺麻烦的,因为有很多细节要处理好,列表控件使用太频繁了,网上也各种自定义的方法,一般的listview自定义肯定会联想到加个头部,然后监听事件加动画,其实方式很多种,今天记录的方式是另外一种方 ...
- Java 内存模型和硬件内存架构笔记
前言 可跟<主存存取和磁盘存取原理笔记>串着看 https://blog.csdn.net/suifeng3051/article/details/52611310 杂技 Java 内存模 ...