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

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


  • 在不同业务场景下,从性能角度考虑,选择唯一索引还是普通索引?依据是什么呢?
  • 回顾: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...

相关推荐
暗恋 懒羊羊13 分钟前
【MySQL】数据类型
数据库·mysql
小Tomkk2 小时前
mysql 最长连续登录天数解析
数据库·mysql
tpoog2 小时前
[MySQL]数据类型
android·开发语言·数据库·mysql·算法·adb·贪心算法
爱吃喵的鲤鱼3 小时前
MySQL增删改查(CRUD)操作详解与实战指南
数据库·mysql
RedCong4 小时前
在k8s中使用CronJob定时备份mysql
mysql·容器·kubernetes
.又是新的一天.5 小时前
02_MySQL安装及配置
android·数据库·mysql
明明明h6 小时前
MySQL 查看本地用户名和密码
数据库·mysql·adb
17´7 小时前
Qt从入门到入土(十一) -数据库操作--MySQL
数据库·c++·qt·mysql·sqlite
八股文领域大手子7 小时前
Spring多数据源环境下的事务与数据源切换
java·数据库·后端·mysql·spring·wpf
SummerGao.8 小时前
ubuntu20.04 APT 安装MySQL Community Server 8
数据库·mysql·ubuntu