我记得之前博客我也写过关于索引使用的文章,但是并不全面,这次尽量针对重点铺全面一点。

因为索引是数据引擎层的结构我们只针对最常见使用的 Innodb 使用的 B+Tree 搜索树结构进行介绍。

每一个在 InnoDB 的中的索引都对应一颗 B+Tree。举个栗子:

创建这样一个表,并且在字段 k 上创建索引

mysql> create table T(
id int primary key,
k int not null,
name varchar(16),
index (k))engine=InnoDB;

这个时候我们插入值

(100,1)、(200,2)、(300,3)、(500,5) 和 (600,6) 这个时候主键的聚簇索引对应一颗树,然后 k 索引值对应一棵树。

基于 Innodb 引擎的特性,一个表只能有一个聚簇索引,聚簇索引上面会记录所有表字段的有序的信息。普通二级索引上面只有该索引字段和主键索引字段的对应信息。(如果可以看得比较明确)。当我们使用语句

select * from xxx where k = x

的时候,我们使用了二级索引。并且由于在二级索引上面没有索引覆盖到 name 字段,所以我们需要在二级索引里面拿到 id = x 的值然后再去聚簇索引树中搜索对应的 name 记录。这个过程被称作回表。

在频繁查询大表特别是字段非常多的表的时候,回表操作是非常消耗性能的。所以当我们设计索引的时候也尽量考虑能进行索引覆盖。也就是直接能在索引列就覆盖到我们需要经常取到的数据而不用回表。我实际中就遇到了类似的栗子,查询一个 5 e 左右的表,消耗高达多余的 50% cpu 都用在回表上面。还好我使用的 TokuDB ,TokuDB 支持多聚簇索引,才解决了这个问题。

索引维护

B+Tree 为了维护索引的有序性需要保持一定的规则和平衡。所以当我们在插入数据的时候就会需要考虑到这些问题。当我们插入一个新的 id 值为 700 ,我们需要在 r5 后面增加一个新的记录。如果插入 id 为 400 就麻烦一点,需要将r4后面的数据向后挪动空出位置。更糟糕的事情是如果 r5 所在的数据页正好满了,我们需要申请一个新的数据页并且挪动一些数据过去,这个过程性能会受到影响。这个过程被称作页分裂,而当我们进行多次分裂之后数据页利用率会变得很低,这是还会触发页的合并。

经常写业务的我们会注意到,目前很多公司的 DBA 都会建议我们使用自增 id 作为表的主键。

自增 id 作为主键有非常多的好处。比如数据拷贝,数据复制等带来的优越性。更重要的是主键递增插入,正好可以让我们避免之前说的挪动数据的情况,让我们的数据一直是以追加的形式增加进数据库的。如果以业务字段做主键,往往很难保证是一直追加。另外不要忘记,我们的二级索引上面存储的是索引列和主键列,如果主键列越小,当然性能就会越高。

使用二级索引查询执行过程

select * from T where k between 3 and 5

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,不满足条件,循环结束。

在这个过程中,回到主键索引那边去查询值的行为我们叫做回表。如果要不回表操作,就需要像我们上面说到的那样进行索引覆盖。如果二级索引上进行了索引覆盖,对应的查询就理所当然不需要回表了。

索引匹配列前缀

B+Tree 可以使用这一原则来进行索引搜寻

这是我们创建的一个二级索引

如果我们查找 like '张%' 的需求的时候,我们会搜到 id3 张六然后继续往后进行搜索直到条件不满足为止。

索引下推

而 MySQL 5.6 引入的索引下推优化(index condition pushdown), 可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。

例如执行:

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

我们有索引 (`name`,`age`) 的索引的情况下,会进行如下优化。

Reference:

本读书笔记皆来自发布在极客时间的 林晓斌(丁奇)的 MySQL 实战45讲:

极客时间版权所有: https://time.geekbang.org/ 版权所有:

https://time.geekbang.org/column/article/69236

https://time.geekbang.org/column/article/69636

https://segmentfault.com/a/1190000008545713   MySQL 中 InnoDB 引擎中页的概念

https://blog.51cto.com/thuhak/1261783   关于 Btree

http://wiki.jikexueyuan.com/project/python-actual-combat/tutorial-11.html   关于 B+tree (附 python 模拟代码)

【MySQL 读书笔记】当我们在使用索引的时候我们在做什么的更多相关文章

  1. 【MySQL 读书笔记】普通索引和唯一索引应该怎么选择

    通常我们在做这个选择的时候,考虑得最多的应该是如果我们需要让 Database MySQL 来帮助我们从数据库层面过滤掉对应字段的重复数据我们会选择唯一索引,如果没有前者的需求,一般都会使用普通索引. ...

  2. 《高性能MySQL》读书笔记之创建高性能的索引

    索引是存储引擎用于快速找到记录的一种数据结构.索引优化是对查询性能优化的最有效手段.索引能够轻易将查询性能提高几个数量级.创建一个最优的索引经常需要重写查询.5.1 索引基础 在MySQL中,存储引擎 ...

  3. 【MySQL 读书笔记】当我们在执行该查询语句的时候我们在干什么

    看了非常多 MySQL 相关的书籍和文章,没有看到过如此优秀的专栏.所以未来一段时间我会梳理读完该专栏的所学所得. 当我们在执行该查询语句的时候我们在干什么 mysql> select * fr ...

  4. 【MySQL 读书笔记】“order by”是怎么工作的?

    针对排序来说,order by 是我们使用非常频繁的关键字.结合之前我们对索引的了解再来看这篇文章会让我们深刻理解在排序的时候,是如何利用索引来达到少扫描表或者使用外部排序的. 先定义一个表辅助我们后 ...

  5. 【MySQL 读书笔记】SQL 刷脏页可能造成数据库抖动

    开始今天读书笔记之前我觉得需要回顾一下当我们在更新一条数据的时候做了什么. 因为 WAL 技术的存在,所以当我们执行一条更新语句的时候是先写日志,后写磁盘的.当我们在内存中写入了 redolog 之后 ...

  6. 【MySQL 读书笔记】RR(REPEATABLE-READ)事务隔离详解

    这篇我觉得有点难度,我会更慢的更详细的分析一些 case . MySQL 的默认事务隔离级别和其他几个主流数据库隔离级别不同,他的事务隔离级别是 RR(REPEATABLE-READ) 其他的主流数据 ...

  7. 【MySQL 读书笔记】全局锁 | 表锁 | 行锁

    全局锁 全局锁是针对数据库实例的直接加锁,MySQL 提供了一个加全局锁的方法, Flush tables with read lock 可以使用锁将整个表的增删改操作都锁上其中包括 ddl 语句,只 ...

  8. MYSQL学习笔记——sql语句优化之索引

    上一篇博客讲了可以使用慢查询日志定位耗时sql,使用explain命令查看mysql的执行计划,以及使用profiling工具查看语句执行真正耗时的地方,当定位了耗时之后怎样优化呢?这篇博客会介绍my ...

  9. 读书笔记 C# 接口中的索引器之浅析

    在C#中,可以在类.结构或接口中用this关键字声明索引器,在索引器内部用get或set访问器访问类中集合的某项值.因此可以将索引器看作是类的属性一样去定义.索引器常用定义格式如下: public i ...

随机推荐

  1. 简述java接口和C++虚类的相同和不同之处

    C++虚类相当于java中的抽象类,与接口的不同处是: 1.一个子类只能继承一个抽象类(虚类),但能实现多个接口 2.一个抽象类可以有构造方法,接口没有构造方法 3.一个抽象类中的方法不一定是抽象方法 ...

  2. .NET Core: 在.NET Core中进行单元测试

    单元测试能够帮助开发人员确保所开发的模块.类以及类中的方法等的正确性,在项目开发过程中,及时进行单元测试能够避免不必要的BUG以及提高测试效率. 在本文中,我们会分别来学习如何使用MSTest.xUn ...

  3. 2016年第七届蓝桥杯javaB组 试题 答案 解析

    1.煤球数目 有一堆煤球,堆成三角棱锥形.具体: 第一层放1个, 第二层3个(排列成三角形), 第三层6个(排列成三角形), 第四层10个(排列成三角形), .... 如果一共有100层,共有多少个煤 ...

  4. springboot源码分析-SpringApplication

    SpringApplication SpringApplication类提供了一种方便的方法来引导从main()方法启动的Spring应用程序 SpringBoot 包扫描注解源码分析 @Spring ...

  5. openlayers 3方法继承

    之前Web GIS开发使用的ArcGIS API用起来很系统,但是使用开源Web GIS API已经成主流趋势(你懂的~),最近项目想要从ArcGIS API 转到openlayers API,用起来 ...

  6. 开源GIS知识

    ---恢复内容开始--- 2.1.3组件层 数据库组件层按照功能可分为两类:数据管理组件和分析组件. 2.1.3.1数据管理组件 (1)GDAL GDAL(http://www.gdal.org/)是 ...

  7. canvas动态图标

    前言 canvas 强大的功能让它成为了 HTML5 中非常重要的部分,至于它是什么,这里就不需要我多作介绍了.而可视化图表,则是 canvas 强大功能的表现之一. 现在已经有了很多成熟的图表插件都 ...

  8. Scrum笔记

    Scrum的笔记,需要的童鞋拿去,有错漏处请指正,谢谢. 出处:https://www.cnblogs.com/Ryu666/p/9890609.html

  9. rabbitmq之确保消息不丢失

    1.背景引入 在使用消息中间件(rabbitmq)时,令开发者最头痛的就是防止消息丢失问题,而消息丢失可能发生的位置主要为三种,分别为(1)消息发送到MQ中消费者消费未成功时突然宕机:(2)消息发送到 ...

  10. jqery autocomplete 动态传递参数的问题

    今天弄一个autocomplete 向后后台动态传递参数的问题 老的写法: params: { "saleid": $("#divSalesman input[field ...