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

因为索引是数据引擎层的结构我们只针对最常见使用的 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. JavaScript夯实基础系列(四):原型

      在JavaScript中有六种数据类型:number.string.boolean.null.undefined以及对象,ES6加入了一种新的数据类型symbol.其中对象称为引用类型,其他数据类 ...

  2. kernel 进阶API

    1. #define cond_resched() ({ \ ___might_sleep(__FILE__, __LINE__, ); \ _cond_resched(); \ }) int __s ...

  3. python学习第五讲,python基础语法之函数语法,与Import导入模块.

    目录 python学习第五讲,python基础语法之函数语法,与Import导入模块. 一丶函数简介 1.函数语法定义 2.函数的调用 3.函数的文档注释 4.函数的参数 5.函数的形参跟实参 6.函 ...

  4. 【转载】java static 关键字的四种用法

    原文链接点这里,感谢博主分享 在java的关键字中,static和final是两个我们必须掌握的关键字.不同于其他关键字,他们都有多种用法,而且在一定环境下使用,可以提高程序的运行性能,优化程序的结构 ...

  5. 基础设施DevOps演进之路

    Related Links:Zuul  https://github.com/Netflix/zuulCAT     https://github.com/dianping/cat Apollo  h ...

  6. 视频文件列表hover添加视频播放按钮

    默认效果图: 鼠标hover效果: 代码如下: <!DOCTYPE html> <html> <head> <meta charset="UTF-8 ...

  7. phpStudy2018安装与配置步骤详解

    phpStudy 2018是一款非常强大的php环境调试工具,一次性安装,无须配置即可使用,是非常方便.好用的PHP调试环境.对学习PHP的新手来说,WINDOWS下环境配置是一件很困难的事:对老手来 ...

  8. Django 传递额外参数及 URL别名

    传递额外参数到视图函数中 在 urls.py 文件中添加下面内容 from django.conf.urls import url urlpatterns = [ url(r'index', view ...

  9. vue px 转rem

    来自:https://www.cnblogs.com/wangqiao170/p/8652505.html 侵 删   每一个认真生活的人,都值得被认真对待 vue px转换为rem 前端开发中还原设 ...

  10. 深圳市共创力咨询CEO杨学明的最新演讲:互联网模式下的企业创新管理

    2018年11月14日, 深圳市共创力咨询董事长.深圳市汇成研发管理咨询公司董事长杨学明先生受邀参加由深圳图书馆主办,深圳手讯视频承办的“倾听行业之声”2018第二届世界CED智慧大会,此次分享的主题 ...