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

因为索引是数据引擎层的结构我们只针对最常见使用的 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. linux下利用nohup后台运行jar文件包程序

    Linux 运行jar包命令如下: 方式一: java -jar XXX.jar 特点:当前ssh窗口被锁定,可按CTRL + C打断程序运行,或直接关闭窗口,程序退出 那如何让窗口不锁定? 方式二 ...

  2. Linux framebuffer deferred io机制

    一.总体框架 deferred io机制主要用于驱动没有实现自刷新同时应用层又不想调用FBIOPAN_DISPLAY的一个折中方案,  使用ioctrl FBIOPAN_DISPLAY好处是节能, 驱 ...

  3. 101 - kube-scheduler源码分析 - k8s源码组织结构概览

    ps:本来应该先发这一篇,再开始讲cobra的,昨天不小心先把 cobra发出去了,今天补上源码概览~ 如上,我们下载好后切换到1.10版本的分支,项目目录结构是这样的(目录部分).有很多,我们先不纠 ...

  4. 从零开始学安全(四十六)●sqli-labs 1-4关 涉及的知识点

    Less-1 到Less-4  基础知识注入 我们可以在 http://127.0.0.1/sqllib/Less-1/?id=1 后面直接添加一个 ‘ ,来看一下效果: 从上述错误当中,我们可以看到 ...

  5. 简简单单的Vue2(简单语法,生命周期,组件)

    既然选择了远方,便只顾风雨兼程! __HANS许 系列:零基础搭建前后端分离项目 系列:零基础搭建前后端分离项目 简单入手 组件 在上面文章,我们简单的讲了前端框架的工程化,也就是MVVM,还有特别聊 ...

  6. [TCP/IP] 数据链路层-ethereal 抓包分析数据帧

    1.下载 http://dx1.pc0359.cn/soft/e/ethereal.rar 2.打开软件,指定抓取的网卡,下面是我抓取自己的主要网卡数据 3.开启个ping命令 , 不停的ping一台 ...

  7. 用python写一个北京市的个税计算器

    #应纳税的钱:税前收入-5000元(起征点)-专项扣除(五险一金等) #工资个税的计算公式为: #个人所得税=应纳税的钱×适用税率-速算扣除数 ''' 1.全月应纳税所得额不超过3000元: 税率:3 ...

  8. oracle学习笔记(六) JDBC使用

    JDBC使用 1. 导包 直接使用IDEA导入依赖包即可 新建一个lib,把jar包放在这里 2. 加载驱动 Class.forName("oracle.jdbc.driver.Oracle ...

  9. Deepin Linux系统的日常使用总结(日常施工)

    1.登录root权限用户 sudo su 2.安装软件语句 apt-get install <package_name> 相对的, 安装:apt-get install <packa ...

  10. element表格切入按钮以及复选框

    1,element表格切入按钮 关键代码: html:<el-table :data="tableList" border style="width: 100%&q ...