一、需要回表的案例

在下面表T中,执行下面语句,需要执行几次树的搜索操作?会扫描多少行?

select * from T where k between 3 and 5

1、初始化语句

mysql> create table T (
ID int primary key,
k int NOT NULL DEFAULT 0,
s varchar(16) NOT NULL DEFAULT '',
index k(k))
engine=InnoDB; insert into T values(100,1, 'aa'),(200,2,'bb'),(300,3,'cc'),(500,5,'ee'),(600,6,'ff'),(700,7,'gg');

2、这条SQL语句的执行流程

1、在 k 索引树上找到 k=3 的记录,取得 ID = 300...
2、再到 ID 索引树查到 ID=300 对应的 R3;
3、在 k 索引树取下一个值 k=5,取得 ID=500;
4、再回到 ID 索引树查到 ID=500 对应的 R4;
5、在 k 索引树取下一个值 k=6,不满足条件,循环结束。

这个过程中回到主键索引树搜索的过程,我们称为回表,可以看到这个查询过程读了K索引树的3条记录
(步骤1、3和5),回表了两次(步骤1、3和5)

二、如何避免回表

在上面的例子中,由于查询结果锁需要的数据只在主键索引上有,所以不得不回表,
那么。有没有可能经过索引优化,避免回表过程?

select ID from T where k between 3 and 5

1、覆盖索引

索引k已经"覆盖了"我们的查询需求。我们称为覆盖索引

由于覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段

2、在一个市民信息表上,是否有必要将身份证号和名字建立联合索引

假设这个市民表的定义是这样的:

CREATE TABLE `tuser` (
`id` int(11) NOT NULL,
`id_card` varchar(32) DEFAULT NULL,
`name` varchar(32) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`ismale` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `id_card` (`id_card`),
KEY `name_age` (`name`,`age`)
) ENGINE=InnoDB

如果现在有一个高频请求,要根据市民的身份证号查询他的姓名,这个联合索引就有意义了,
它可以在这个高频请求上用覆盖索引、不再需要回表查整行记录,减少语句的执行时间

3、回表的缺点

当然、索引字段的维护总是有代价的,建立冗余索引来支持覆盖索引时就需要权衡考虑了,这正是业务DBA,或者称为业务数据架构师的工作

三、最左前缀原则

1、疑问

单独为一个不频繁的请求创建一个索引又感觉有点浪费,应该怎么做呢?

2、解决方案

B+树这种索引结构,可以利用索引的"最左前缀",来定位记录

 

1、为了直观地说明这个概念、我们用(name、age)这个联合索引来分析

1、查到所有名字是“张三”的人

快速定位到ID4,然后向后遍历得到所有需要的结果

2、你要查的是所有名字第一个字是“张”的人

where name like '张%'

查找到第一个符合条件的记录是ID3,然后向后遍历,知道不满足条件为止。
你要查的是所有名字第一个字是“张”的人

不只是索引的全部定义,只要满足最左前缀,就可以可利用索引来加速检索、这个最左前缀可以是联合索引的最左N个字段,也可以是字符串索引的最左M个字符

3、在建立联合索引的时候,如何安排索引内的字段顺序

1、评估标准

索引的复用能力,

因为可以支持最左前缀,所以已经有了(a,b)这两个联合所用后,一般就不需要单独在b上面建立索引了

2、第一原则是

如果通过调整顺序,可以减少维护一个索引。那么这个顺序往往就是需要优先考虑采用的

3、既有联合查询,又有基于 a、b 各自的查询呢?

同时维护(a,b)(b)这两个索引、这时候我们要考虑的原则就是空间了。

比如上面这个市民表的情况、name字段是比age字段大的,那我就建议你创建一个(name,age)的联合索引和一个(age)的字段索引

四、索引下推

我们还是以市民表的联合索引(name, age)为例。检索出表中:"名字第一个字是长,而年龄是10岁的所有男孩"

1、名字第一个字是长,而年龄是10岁的所有男孩

1、SQL语句是这么写的

mysql> select * from tuser where name like '张 %' and age=10 and ismale=1;

1、 找到第一个满足条件的记录ID3(这还不错,总比权标扫描要好)
2、判断其他是否满足条件

3、无索引执行流程

5.6之前只能从ID3开始一个一个回表,到主键索引上找出数据航,再对比字段值不去判断age

执行流程

每一个虚线箭头表示回表一次

1、InnoDB 并不会去看 age的值,
2、只是按顺序把name的第一个子是'张'的记录一条取出来回表,因此需要回表4次

4、索引下推执行流程

5.6之后引入的索引下推优化,可以在索引遍历过程中对索引中包含的字段先判断,直接过滤掉不满足条件的记录,减少回表次数
内部就判断了age是否等于10

执行流程

每一个虚线箭头表示回表一次

1、InnoDB 内部就哦按段了age是否等于10,
2、对不等于10的记录,直接判断跳过,在我们这个例子中只需要对ID4、ID4回表2次

五、联合索引的技巧

1、覆盖索引

如果查询条件使用的是普通索引(或是联合索引的最左原则字段),查询结果是联合索引的字段或是主键,不用回表操作,直接返回结果,减少IO磁盘读写读取正行数据

2、最左前缀

联合索引的最左 N 个字段,也可以是字符串索引的最左 M 个字符

3、联合索引

根据创建联合索引的顺序,以最左原则进行where检索,比如(age,name)以age=1 或 age= 1 and name=‘张三’可以使用索引,单以name=‘张三’ 不会使用索引,考虑到存储空间的问题,还请根据业务需求,将查找频繁的数据进行靠左创建索引。

4、索引下推

like 'hello%’and age >10 检索,MySQL5.6版本之前,会对匹配的数据进行回表查询。5.6版本后,会先过滤掉age<10的数据,再进行回表查询,减少回表率,提升检索速度

MySQL实战45讲学习笔记:索引(第五讲)的更多相关文章

  1. 深挖计算机基础:MySQL实战45讲学习笔记

    参考极客时间专栏<MySQL实战45讲>学习笔记 一.基础篇(8讲) MySQL实战45讲学习笔记:第一讲 MySQL实战45讲学习笔记:第二讲 MySQL实战45讲学习笔记:第三讲 My ...

  2. MySQL实战45讲学习笔记:第三十九讲

    一.本节概况 MySQL实战45讲学习笔记:自增主键为什么不是连续的?(第39讲) 在第 4 篇文章中,我们提到过自增主键,由于自增主键可以让主键索引尽量地保持递增顺序插入,避免了页分裂,因此索引更紧 ...

  3. MySQL实战45讲学习笔记:第十五讲

    一.引子 在今天这篇答疑文章更新前,MySQL 实战这个专栏已经更新了 14 篇.在这些文章中,大家在评论区留下了很多高质量的留言.现在,每篇文章的评论区都有热心的同学帮忙总结文章知识点,也有不少同学 ...

  4. MySQL实战45讲学习笔记:第九讲

    一.今日内容概要 今天的正文开始前,我要特意感谢一下评论区几位留下高质量留言的同学.用户名是 @某.人 的同学,对文章的知识点做了梳理,然后提了关于事务可见性的问题,就是先启动但是后提交的事务,对数据 ...

  5. MySQL实战45讲学习笔记:第二十四讲

    一.引子 在前面的文章中,我不止一次地和你提到了 binlog,大家知道 binlog 可以用来归档,也可以用来做主备同步,但它的内容是什么样的呢?为什么备库执行了 binlog 就可以跟主库保持一致 ...

  6. MySQL实战45讲学习笔记:事务隔离级别(第三讲)

    一.隔离性与隔离级别 1.事务的特性 原子性 一致性 隔离性 持久性 2.不同事务隔离级别的区别 读未提交:别人改数据的事务尚未提交,我在我的事务中也能读到.读已提交:别人改数据的事务已经提交,我在我 ...

  7. MySQL实战45讲学习笔记:第十三讲

    一.引子 经常会有同学来问我,我的数据库占用空间太大,我把一个最大的表删掉了一半的数据,怎么表文件的大小还是没变? 那么今天,我就和你聊聊数据库表的空间回收,看看如何解决这个问题. 这里,我们还是针对 ...

  8. MySQL实战45讲学习笔记:第二十二讲

    一.引子 不知道你在实际运维过程中有没有碰到这样的情景:业务高峰期,生产环境的 MySQL 压力太大,没法正常响应,需要短期内.临时性地提升一些性能. 我以前做业务护航的时候,就偶尔会碰上这种场景.用 ...

  9. MySQL实战45讲学习笔记:第十四讲

    一.引子 在开发系统的时候,你可能经常需要计算一个表的行数,比如一个交易系统的所有变更记录总数.这时候你可能会想,一条 select count(*) from t 语句不就解决了吗? 但是,你会发现 ...

随机推荐

  1. 将对象xml序列化和反序列化

    //将一个对象按XML序列化的方式写入到一个文件,使用的默认的UTF8编码格式 //o为要序列化的对象 //path保存文件的路径 public static object  _lockObj=new ...

  2. Chrome 清除当前网站下的缓存

    打开开发者工具(F12),选择 Network--Disable cache 即可.需要清除某网站缓存时 F12 打开开发者工具就会自动清除这个网站的缓存,而不必清除所有网站的缓存了. 如评论中大佬所 ...

  3. RocketMQ4.3.x 史上配置最全详解,没有之一

    最近整理了RocketMQ的配置参数一部分参考rocketmq技术内幕,一部分自己看源码猜测,有表述不清楚或不正确请广大网友指正 这里应该是最全的配置解析了,搞了2天.以后查询就好办了,仅此贡献给广大 ...

  4. vue源码分析—Vue.js 源码目录设计

    Vue.js 的源码都在 src 目录下,其目录结构如下 src ├── compiler # 编译相关 ├── core # 核心代码 ├── platforms # 不同平台的支持 ├── ser ...

  5. Shell企业案例实战和企业面试题

    shell企业面试题 1.批量创建带有随机小写字符文件程序 使用for循环在/pizza目录下创建10个html文件,其中每个文件包含10个随机小写字母加固定字母_pizza 1.思路分析: 核心是: ...

  6. Python协程的引入与原理分析

    相关概念 并发:指一个时间段内,有几个程序在同一个cpu上运行,但是任意时刻只有一个程序在cpu上运行.比如说在一秒内cpu切换了100个进程,就可以认为cpu的并发是100. 并行:值任意时刻点上, ...

  7. 通过java代码执行Linux命令查询声卡和显卡 型号

    package test; import java.io.BufferedReader; import java.io.InputStreamReader; public class ExcuteLi ...

  8. C#之事件与eventArgs

    static void Main(string[] args)         {             MyText myText = new MyText();             myTe ...

  9. mysql提取.sql备份文件中的单个表以及表数据

    背景:随着业务模块的不断在增多,数据库mysql容量也是越来越大,做测试时,整个备份还原比较耗费时间,由于有时候仅仅需要单个表或者少数几个表,要想从整个备份文件中提取指定的表以及数据,需要以下方法. ...

  10. JS对JSON对象遍历输出的时候真的是按照顺序输出吗?

    对象的遍历输出并不是按照对象属性定义顺序来的,那么是按照什么规则来的呢,仔细深入研究你会发现,这还跟浏览器有关系,Chrome跟IE是不一样的,所以给出以下结论: Chrome Opera 的 Jav ...