性能对决:普通索引与唯一索引的底层博弈

性能对决:普通索引与唯一索引的底层博弈


  • 在不同业务场景下,从性能角度考虑,选择唯一索引还是普通索引?依据是什么呢?
  • 回顾:InnoDB 的索引组织结构

9.1 查询

示例 SQL: select id from T where k=5。

  1. 普通索引

    • 对于普通索引 来说,查找到满足条件的第一条记录(5,500)后,需要再查找下一个记录,直到碰到第一个不满足 k=5 条件的记录。
  2. 唯一索引

    • 对于唯一索引 来说,由于索引定义了唯一性,查找到第一个满足条件的记录后,就会停止继续检索。
  3. **不同索引带来的性能差距会有多少呢?**答案是:微乎其微。

    • InnoDB 的数据是按数据页为单位来读写的。也就是说,当需要读一条记录的时候,并不是将这个记录本身从磁盘读出来,而是以页为单位,将其整体读入内存。InnoDB 中,每个页的大小默认是 16 KB。
    • 对于普通索引来说,要多做那一个"查找和判断下一条记录"的操作,就只需要一次指针寻找和计算。
    • 如果 k=5 记录刚好是这个数据页的最后一个记录,那么要取下一个记录,必须读取下一个数据页,这个操作会稍微复杂一些。(这种情况的概率会很低。对于整型字段,一个数据页可以放近千个 key。)

9.2 更新

说明普通索引和唯一索引对更新语句的性能影响时,先来介绍下 change buffer。

9.2.1 change buffer
  • 当需要更新一个数据页时,如果数据页在内存中就直接更新,而如果这个数据页还没有在内存中的话,在不影响数据一致性的前提下,InnoDB 会将这些更新操作缓存在 change buffer 中,这样就不需要从磁盘中读入这个数据页了。
  • 在下次查询需要访问这个数据页的时候,将数据读入内存,然后执行 change buffer 中与这个页有关的操作。
  • 通过上面这个方式就能保证这个数据逻辑的正确性。
  • change buffer 是可以持久化的数据。也就是说,change buffer 在内存中有拷贝,也会被写入到磁盘上。
  • 将 change buffer 中的操作应用到原数据页,得到最新结果的过程称为 merge 。除了访问这个数据页会触发 merge 外,系统有后台线程会定期 merge 。在数据库正常关闭(shutdown)的过程中,也会执行 merge 操作。
  • 显然,如果能够将更新操作先记录在 change buffer,减少磁盘,语句的执行速度会得到明显的提升 。而且,数据读入内存是需要占用 buffer pool 的,所以,这种方式还能够避免占用内存,提高内存利用率。
9.2.2 change buffer 的使用
  1. 只有普通索引可以使用 change buffer。唯一索引的更新就不能使用 change buffer。

  2. change buffer 用的是 buffer pool 里的内存,因此,不能无限增大。

    可以通过 innodb_change_bufferb_max_size 来设置。

9.2.3 在表中插入一个新记录(4,400),InnoDB 的处理流程
  1. 这个记录要更新的目标页,在内存中 。
    • 唯一索引 ,找到 3 和 5 间的位置,判断到没有冲突,插入这个值,语句执行结束。
    • 普通索引,找到 3 和 5 间的位置,插入这个值,语句执行结束。
    • 上面两种的差别只有一个判断,只会耗费微小的 CPU 时间。
  2. 这个记录要更新的目标页,不在内存中 。
    • 唯一索引,将数据页读入内存(磁盘 IO 操作),判断到没有冲突,插入这个值,语句执行结束。
    • 普通索引 ,将数据记录在 change buffer,语句执行结束。
    • 从这里看出,change buffer 减少了磁盘 IO 访问,对更新性能的提升是会很明显的。

9.2.4 change buffer 的使用场景

  • 在写多读小的业务,change buffer 的使用效果最好。

    因为 merge 的时候,是真正进行数据更新的时刻,

    而 change buffer 的主要目的就是将记录的变更动作缓存下来。

    所以,在一个数据页做 merge 前,change buffer 记录的变更越多,收益越大。

9.3 索引选择和实践

  1. 建议尽量选择普通索引。

    普通索引和唯一索引在查询能力上没差别,主要考虑的是对更新性能的影响。

  2. 如果,更新后面,马上伴随着查询,那么你应该关闭 change buffer。

9.4 change buffer 和 redo log

  1. redo log 主要节省的是随机写磁盘的 IO 消耗(转成顺序写)。
  2. change buffer 主要节省的则是随机读磁盘的 IO 消耗。

9.5 小结

  • 在业务接受的情况下,建议优先考虑普通索引。

    唯一索引用不上 change buffer 的优化机制。

  • 参考引用:

    参考:time.geekbang.org/column/arti...

相关推荐
.Hypocritical.3 小时前
MySQL |常用 SQL 语句与 pymysql 函数
mysql
NineData3 小时前
MySQL 到 Doris 实时数据同步:订单、用户和日志数据入仓方案
数据库·mysql
Dovis(誓平步青云)4 小时前
现场问题先关闭还是先验收,建筑任务怎样处理依赖
前端·javascript·数据库·mysql·音视频
xuefuhe5 小时前
MySQL:group_replication_start_on_boot vs group_replication_bootstrap_group
mysql
for_ever_love__6 小时前
MySQL Online DDL 完全指南:INSTANT/INPLACE/COPY 三种算法、MDL 锁事故与 gh-ost 实战
数据库·mysql·ddl·online·gh-ost·锁表·加字段
for_ever_love__6 小时前
MySQL 子查询、派生表与 CTE 优化:半连接、物化和递归实战
数据库·mysql·优化·as·子查询·with·cte
鱼很腾apoc7 小时前
【MySQL】 第1期 从核心概念到表约束全解析
linux·c语言·数据库·学习·mysql
斯内普吖9 小时前
(开源)校园充电宝租借管理系统实战指南 基于 Java + SSM + Vue + MySQL
java·vue.js·mysql·开源
啵啵啵鱼9 小时前
对数据的增删改查
数据库·mysql·ai·idea·ai编程·navicat·obsidian
靠沿9 小时前
MySQL数据库基础——索引的使用&alter、explain关键字
java·数据库·mysql