【MySQL 读书笔记】当我们在使用索引的时候我们在做什么
我记得之前博客我也写过关于索引使用的文章,但是并不全面,这次尽量针对重点铺全面一点。
因为索引是数据引擎层的结构我们只针对最常见使用的 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 读书笔记】当我们在使用索引的时候我们在做什么的更多相关文章
- 【MySQL 读书笔记】普通索引和唯一索引应该怎么选择
通常我们在做这个选择的时候,考虑得最多的应该是如果我们需要让 Database MySQL 来帮助我们从数据库层面过滤掉对应字段的重复数据我们会选择唯一索引,如果没有前者的需求,一般都会使用普通索引. ...
- 《高性能MySQL》读书笔记之创建高性能的索引
索引是存储引擎用于快速找到记录的一种数据结构.索引优化是对查询性能优化的最有效手段.索引能够轻易将查询性能提高几个数量级.创建一个最优的索引经常需要重写查询.5.1 索引基础 在MySQL中,存储引擎 ...
- 【MySQL 读书笔记】当我们在执行该查询语句的时候我们在干什么
看了非常多 MySQL 相关的书籍和文章,没有看到过如此优秀的专栏.所以未来一段时间我会梳理读完该专栏的所学所得. 当我们在执行该查询语句的时候我们在干什么 mysql> select * fr ...
- 【MySQL 读书笔记】“order by”是怎么工作的?
针对排序来说,order by 是我们使用非常频繁的关键字.结合之前我们对索引的了解再来看这篇文章会让我们深刻理解在排序的时候,是如何利用索引来达到少扫描表或者使用外部排序的. 先定义一个表辅助我们后 ...
- 【MySQL 读书笔记】SQL 刷脏页可能造成数据库抖动
开始今天读书笔记之前我觉得需要回顾一下当我们在更新一条数据的时候做了什么. 因为 WAL 技术的存在,所以当我们执行一条更新语句的时候是先写日志,后写磁盘的.当我们在内存中写入了 redolog 之后 ...
- 【MySQL 读书笔记】RR(REPEATABLE-READ)事务隔离详解
这篇我觉得有点难度,我会更慢的更详细的分析一些 case . MySQL 的默认事务隔离级别和其他几个主流数据库隔离级别不同,他的事务隔离级别是 RR(REPEATABLE-READ) 其他的主流数据 ...
- 【MySQL 读书笔记】全局锁 | 表锁 | 行锁
全局锁 全局锁是针对数据库实例的直接加锁,MySQL 提供了一个加全局锁的方法, Flush tables with read lock 可以使用锁将整个表的增删改操作都锁上其中包括 ddl 语句,只 ...
- MYSQL学习笔记——sql语句优化之索引
上一篇博客讲了可以使用慢查询日志定位耗时sql,使用explain命令查看mysql的执行计划,以及使用profiling工具查看语句执行真正耗时的地方,当定位了耗时之后怎样优化呢?这篇博客会介绍my ...
- 读书笔记 C# 接口中的索引器之浅析
在C#中,可以在类.结构或接口中用this关键字声明索引器,在索引器内部用get或set访问器访问类中集合的某项值.因此可以将索引器看作是类的属性一样去定义.索引器常用定义格式如下: public i ...
随机推荐
- Fescar(Seata)-Springcloud流程分析-1阶段
Fescar是阿里18年开源的分布式事务的框架.Fescar的开源对分布式事务框架领域影响很大.作为开源大户,Fescar来自阿里的GTS,经历了好几次双十一的考验,一经开源便颇受关注.今天就来看了F ...
- @vue-cli3创建项目报错:ERROR command failed: npm install --loglevel error --registry=https://registry.npm.taobao.org --di
使用@vue-cli3时 在你感觉所以配置都搞好开始创建项目时,不停的报错,就是创建不成功 清npm缓存也不行 改淘宝镜像也不行 就快奔溃了,最后最终(其实我在凑150字,为了能发到首页给更多采坑的兄 ...
- Java服务器内存过高&CPU过高问题排查
一.内存过高 1.内存过高一般有两种情况:内存溢出和内存泄漏 (1)内存溢出:程序分配的内存超出物理机的内存大小,导致无法继续分配内存,出现OOM报错 (2)内存泄漏:不再使用的对象一直占据着内存不释 ...
- Spring Cloud Alibaba基础教程:Sentinel使用Nacos存储规则
通过上一篇<使用Sentinel实现接口限流>的介绍,相信大家对Sentinel已经有了初步的认识.在Spring Cloud Alibaba的整合封装之下,接口限流这件事情可以非常轻易的 ...
- 论AOP面向切面编程思想
原创: eleven 原文:https://mp.weixin.qq.com/s/8klfhCkagOxlF1R0qfZsgg [前言] AOP(Aspect-Oriented Programming ...
- 用于ViEmu的重置为试用状态的Python脚本
import winreg import shutil shutil.rmtree("C:\\Users\\Administrator\\AppData\\Local\\Identities ...
- c#封装DBHelper类
public enum EffentNextType { /// <summary> /// 对其他语句无任何影响 /// </summary> None, /// <s ...
- h5与c3权威指南笔记--css3结构性伪类选择器root,not,empty,target
root:将样式绑定到根元素(html中的根元素是<html></html>) 举个栗子 :root{ background-color: yellow; } body{ ba ...
- Android破解学习之路(十五)—— 【Unity3D】洛菲斯的呼唤(Lophis roguelike)无限金币(道具)的实现 破解
前言 之前玩月圆之夜玩的挺high的,最近又找到了个与月圆之夜类似的卡牌游戏,游戏名为Lophis roguelike,中文翻译名洛菲斯的呼唤. 但是这个与月圆之夜有所不同,如果失败了,只能从开头重新 ...
- <3>Centos系统完整安装python流程
一.环境 系统:Centos7 Python:3.6.5 自带pip.setuptools 二.命令 介绍:因为yum是依赖于python2,所以千万别删除自带的python2,下面的方法就是py2 ...