数据库|从头开始搞懂 MySQL(06)索引的选择

我们已经了解了唯一索引和普通索引的区别,那么在不同的业务场景下,我们应该选择普通索引还是唯一索引呢?
我们还是使用第 4 篇文章 索引 中的例子来说明,假设字段 card 上的值都不重复
数据库|从头开始搞懂 MySQL(06)索引的选择
文章图片

我们从这两种索引对查询语句和更新语句的性能影响来进行分析
1、查询过程 【数据库|从头开始搞懂 MySQL(06)索引的选择】执行的 SQL:
SELECT ID FROM test WHERE card = 122234
这个查询语句在索引树上,先是通过 B+ 树从根节点开始,然后按层搜索到叶子结点,也就是中间这个数据页,然后可以认为数据页内部通过二分法来定位记录
InnoDB 的数据是按照页为单位来读写的,当需要读取一条记录的时候,会以页为单位,将其整体读入内存,每个数据页的大小默认为 16KB
  • 对于普通索引来说,查找到满足条件的第一个记录(122234,50)之后,要查找下一个记录,直到碰到第一个不满足条件 card = 122234 的记录
  • 对于唯一索引来说,索引是唯一的,查到第一个满足条件的记录后就停止检索
因为引擎按页进行读取,当找到 card = 122234 的记录的时候,它所在的数据页就已经在内存里了,对于普通索引来说,要多做的查找并判断下一条记录的操作就只需要一次指针寻找和一次计算,如果这个记录是数据页的最后一个记录,这个操作会复杂一些,读取下一个数据页,这个概率几乎可以忽略不计
2、更新过程 2.1 change buffer 普通索引和唯一索引对更新更新语句的性能有什么影响呢?我们先来看一下 change buffer
当要更新一个数据页时,如果数据页在内存中就直接更新,如果不在内存中的话,在不影响数据一致性的前提下,InnoDB 会将这些更新操作缓存在 change buffer 中,这样就不需要从磁盘中读入这个数据页了,在下次查询需要访问这个数据页的时候,将数据页读入内存,然后执行 change buffer 中与这个页相关的操作,保证数据准确性
虽然名字叫做 change buffer,实际上 change buffer 在内存中有拷贝,会持久化到磁盘上
purge
将 change buffer 中的操作应用到原数据页,得到最新结果的过程称之为 purge,除了访问这个数据页会触发 purge 外,系统中有后台线程会定期执行 purge,数据库正常关闭过程中也会执行 purge 操作
2.1.1 change buffer 使用
唯一索引的更新操作,都要先判断操作是否违反唯一性约束,比如要插入一条记录,会先查表中是否已经存在,这样会将数据页先读入内存中判断,已经读入到内存中的话直接更新内存会更快,没有必要使用 change buffer,唯一索引更新不能使用 change buffer
change buffer 使用的是 buffer pool 里面的内存,大小可以通过 innodb_change_buffer_max_size 来设置,value 值表示 change buffer 大小能占用 buffer pool 的百分比
数据库|从头开始搞懂 MySQL(06)索引的选择
文章图片

如果我们要在表中插入一条新的记录(12345, 3),InnoDB 的处理流程如下
如果要更新的目标页在内存中:
  • 对于唯一索引,找到 2 和 4 之间的位置,判断没有冲突就插入这个值,语句执行结束
  • 对于普通索引,找到 2 和 4 之间的位置,插入这个值,语句执行结束
如果要更新的目标页不在内存
  • 对于唯一索引,先将数据页读入内存,判断没有冲突,插入值,语句执行结束
  • 对于普通索引,将记录更新在 change buffer,语句执行结束
将数据从磁盘读入内存会涉及随机 IO 的访问,操作的成本较高,change buffer 减少了随机磁盘访问,所以对更新性能的提升会比较明显
2.1.2 change buffer 使用场景
因为 purge 的时候是真正的数据进行更新的时候,change buffer 的主要目的就是将记录的变更动作缓存下来,所以在一个数据页 purge 之前,change buffer 记录越多,更新次数越多,收益就越大
  • 在对于一个写多读少的业务来说,比如订单流水、日志系统等,页面在写完后马上查询的概率较小,比较适合 change buffer 使用
  • 对于写入后立马查询的业务,即使满足了条件先将更新记录在 change buffer 中,但之后立马查询该数据页,就会触发 purge,会增加 IO 次数,不适合 change buffer 使用
如果
索引选择
  • 普通索引和唯一索引在查询能力上区别不大,主要考虑对更新性能的影响,尽量还是考虑使用普通索引
  • 如果在更新后立马伴随对记录的查询,可以关闭 change buffer,其它情况 change buffer 是可以提交性能的

    推荐阅读