MySQL中的Change Buffer是什么,它有什么作用?
MySQL 中的 Change Buffer(更改缓冲区)是 InnoDB 存储引擎使用的一种特殊数据结构,主要用于优化对二级索引(secondary indexes)的写操作性能。
它的核心作用是:
当对表进行 INSERT
、UPDATE
或 DELETE
操作(DML操作)时,如果这些操作需要修改二级索引,并且这些二级索引页(pages)当前不在缓冲池(Buffer Pool)中,Change Buffer 会将这些更改缓存起来,而不是立即从磁盘读取相应的索引页进行修改。
为什么这样做有好处?
-
减少随机I/O:
- 与聚簇索引(clustered index)不同,二级索引的插入通常是相对随机的,更新和删除也可能影响到磁盘上不连续的二级索引页。
- 如果每次修改都立即去磁盘读取这些分散的二级索引页,会产生大量的随机I/O操作,这对于传统的机械硬盘(HDD)来说是非常昂贵的,会显著降低性能。
- Change Buffer 通过将这些更改先缓存起来,避免了立即的随机磁盘读取。
-
延迟合并,批量处理:
- 缓存的更改会在稍后的某个时间点被合并(merge)到实际的二级索引页中。这通常发生在以下情况:
- 当这些索引页因为其他读操作(例如查询)而被加载到缓冲池时。
- 当系统比较空闲时,后台的
purge
线程会定期将更新后的索引页写回磁盘。 - 在数据库缓慢关闭(slow shutdown)期间。
- 通过延迟合并,可以将多次对同一索引页的修改一次性完成,或者将对附近索引页的修改集中处理,从而将随机I/O转换为更高效的顺序I/O(或者至少是更少次数的随机I/O)。
- 缓存的更改会在稍后的某个时间点被合并(merge)到实际的二级索引页中。这通常发生在以下情况:
关键点:
- 只针对二级索引: Change Buffer 主要用于非唯一的二级索引。对于唯一二级索引,由于需要立即检查唯一性约束,所以插入操作通常不能被缓冲。聚簇索引的修改是直接进行的,不通过 Change Buffer。
- 内存与磁盘:
- 在内存中,Change Buffer 是缓冲池(Buffer Pool)的一部分。
- 在磁盘上,当数据库关闭时,Change Buffer 的内容会持久化到系统表空间(system tablespace)中,确保数据不会丢失。
- 适用场景:
- 对于 I/O 密集型的工作负载(例如,大量 DML 操作,特别是批量插入)尤其有价值。
- 当数据集远大于缓冲池,导致二级索引页频繁地不在内存中时。
- 配置参数:
innodb_change_buffering
: 控制哪些类型的操作(inserts, deletes, purges, all, none)会被缓冲。值得注意的是,从 MySQL 8.0.20 和 MySQL 8.4 开始,由于 SSD 的普及(随机I/O性能远好于HDD),这个参数的默认值可能已经更改为none
或推荐根据实际情况考虑是否禁用它。innodb_change_buffer_max_size
: 配置 Change Buffer 可以占用的缓冲池的最大百分比(默认为25%,最大可到50%)。
- 潜在影响:
- 虽然 Change Buffer 可以提高写性能,但它会占用缓冲池的一部分空间,减少了可用于缓存数据页的内存。
- 在某些情况下,例如当有大量缓存的更改需要合并时,合并过程本身可能会增加磁盘I/O,短期内可能对查询性能产生影响。
- 如果工作数据集完全适合缓冲池,或者二级索引很少,禁用 Change Buffer 可能更有利。
总结来说,Change Buffer 是 InnoDB 为了减少因修改二级索引而产生的大量随机磁盘I/O,通过缓存这些更改并延迟批量合并来提升写密集型操作性能的一种机制。 然而,随着存储技术的发展(尤其是SSD的广泛应用),其必要性和默认配置也在发生变化,需要根据具体的硬件环境和工作负载进行评估和调整。
回答重点
Change Buffer 是MySQL InnoDB存储引擎中的一个机制,用于暂存对二级索引的插入和更新操作的变更,而不立即执行这些操作,随后,当InnoDB进行合适的条件时(如页被读取或Flush操作),会将这些变更写入到二级索引中。
作用:
- 提高写入性能:通过将对二级索引的变更暂存,可以减少对磁盘的频繁写入,提升插入和更新操作的性能。
- 批量处理:Change Buffer可以在后续的操作中批量处理这些变更,减少了随机写入的开销。
扩展知识
进一步理解Change Buffer
-
那change buffer具体是个什么东西呢?
如果当前表针对name有一个二级索引。假设我们执行一条update table set name = 'yes' where id = 1
(这条语句需要修改name这个二级索引中的数据) ,此时buffer pool并没有对应二级索引的索引页数据。
这个时候需要把索引页加载才内存中立即执行修改吗?
不是的,这时候change buffer就上场了。
如果当前二级索引页不在buffer pool中,那么innodb会把更新操作缓存到change buffer中,当下次访问到这条数据后,会把索引页加载到buffer pool中,并且应用上change buffer里面的变更,这样就保证了数据的一致性。
上述SQL中,change buffer中会存储 name 字段的旧索引值删除操作和新索引值插入操作。 -
所以change buffer有什么好处?
当二级索引页不在buffer pool中时,change buffer可以避免立即从磁盘读取对应索引页导致的昂贵的随机I/O,对应的更改可以在后面当二级索引页读入buffer pool时候被批量应用。
看到我加粗的字体没,二级索引页,没错change buffer只能用于二级索引的更改,不适用于主键索引,空间索引以及全文索引。
还有,唯一索引也不行,因为唯一索引需要读取数据然后检查数据的一致性。 -
更改先缓存在change buffer中,假如数据库挂了,更改不是丢了吗?
别怕,change buffer也是要落盘存储的,从上图我们看到change buffer会落盘到系统表空间里面,然后redo log也会记录chang buffer的修改来保证数据一致性。
至此,想必你对change buffer已经有一定了解了吧。它主要用来避免于二级索引页修改产生的随机I/O。如果你的内存够大能装下所有数据,或者二级索引很少,或者你的磁盘是固态的对随机访问影响不大,其实可以关闭change buffer,因为它也增加了复杂度,当然最终还是得看压测结果。
Change Buffer的大小
- Change Buffer的大小可以通过系统变量 innodb_change_buffer_max_size 进行配置,默认值为25%的InnoDB缓冲池大小,最大值可以设置为50%。合理配置可以提升性能,但过大可能导致内存不足。