0

mysql之Change Buffer

2024.08.11 | cuithink | 100次围观

在 MySQL5.5 之前,叫插入缓冲(Insert Buffer),只针对 INSERT 做了优化;现在对 DELETE 和 UPDATE 也有效,叫做写缓冲(Change Buffer)。它是一种应用在非唯一普通索引页(non-unique secondary index page)不在缓冲池中,对页进行了写操作,并不会立刻将磁盘页加载到缓冲池,而仅仅记录缓冲变更(Buffer Changes),等未来数据被读取时,再将数据合并(Merge)恢复到缓冲池中的技术。写缓冲的目的是降低写操作的磁盘 IO,提升数据库性能。

数据的修改分为两个情况:

  1. 当修改的数据页在缓冲池时

通过 LRU、Flush List 的管理,数据库不是直接写入磁盘中,是先将 redo log 写入到磁盘,再通过 checkpoint 机制,将这些 “脏数据页” 同步地写入磁盘,等于是将这期间发生的 n 次的落盘合并成了一次落盘。因为有 redo log 是落盘的,所以即使数据库崩溃,缓存中的数据页全部丢失,也可以通过 redo log 将这些数据页找回来。

redo log 是数据库用来在崩溃的时候进行数据恢复的日志,redo log 的写入策略可以通过参数控制,并不一定是每一次写操作之后立即落盘 redo log,在部分参数下,redo log 可能是每秒集中写入一次,也有可能采取其他落盘策略,但是无论采用什么方式,redo log 的量都是不会减少的,与数据写入的覆盖性不同,后一条 redo log 是不会覆盖前一条的,而是增量形式的,因此写 redo log 的操作,等同于是对磁盘某一小块区域的顺序 I/O,而不像数据落盘一样的随机 IO 在磁盘里写入,需要磁盘在多个地方移动磁头。所以 redo log 的落盘是 IO 操作当中消耗较少的一种,比数据直接刷回磁盘要优很多。

  1. 当修改的数据页不在缓冲池时,不用写缓冲至少需要下面的三步:

  • 先把需要的索引页,从磁盘加载到缓冲池,一次磁盘随机读操作;

  • 修改缓冲池中的页,一次内存操作;

  • 写入 redo log ,一次磁盘顺序写操作;

在没有命中缓冲池的时候,至少多产生一次磁盘 IO,对于写多读少的业务场景,性能损耗是很高的

加入写缓冲优化后,流程优化为:

  • 在写缓冲中记录这个操作,一次内存操作;

  • 写入 redo log,一次磁盘顺序写操作;

其性能与这个索引页在缓冲池中,相近。

  1. 如何保证数据的一致性?

  • 数据库异常奔溃,能够从 redo log 中恢复数据;

  • 写缓冲不只是一个内存结构,它也会被定期刷盘到写缓冲系统表空间;

  • 数据读取时,有另外的流程,将数据合并到缓冲池;

下一次读到该索引页:

  • 载入索引页,缓冲池未命中,这次磁盘 IO 不可避免;

  • 从写缓冲读取相关信息;

  • 恢复索引页,放到缓冲池 LRU 和 Flush 里;(在真正被读取时,才会被加载到缓冲池中)

  1. 为什么写缓冲优化,仅适用于非唯一普通索引页呢?

InnoDB 里有聚集索引(Clustered Index)) 和普通索引 (Secondary Index) 两种。如果索引设置了唯一(Unique)属性,在 进行修改操作 时, InnoDB 必须进行唯一性检查 。也就是说, 索引页即使不在缓冲池,磁盘上的页读取无法避免(否则怎么校验是否唯一!?)

此时就应该直接把相应的页放入缓冲池再进行修改。

  1. 除了数据页被访问,还有哪些场景会触发刷写缓冲中的数据呢?

  • 有一个后台线程,会认为数据库空闲时;

  • 数据库缓冲池不够用时;

  • 数据库正常关闭时;

  • redo log 写满时;(几乎不会出现 redo log 写满,此时整个数据库处于无法写入的不可用状态)

  1. 什么业务场景,适合开启 InnoDB 的写缓冲机制?

  • 数据库大部分是非唯一索引;

  • 业务是写多读少,或者不是写后立刻读取;


粤ICP备16076548号
发表评论