MySQL 的 Buffer Pool 和 Change Buffer 是如何加快数据的读写速度的?

39 阅读4分钟

首先明确二者定位:Buffer Pool(缓冲池) 是 InnoDB 核心内存区域,缓存高频访问的「数据页/索引页」;Change Buffer(写缓冲) 是 Buffer Pool 的特殊分区,仅缓存「非唯一二级索引页」的写操作。二者分工协作,分别从“读写通用缓存”和“索引写优化”角度加速数据读写,具体逻辑如下:

一、Buffer Pool:通过“页级缓存”加速通用读写

Buffer Pool 是基础,核心是将“磁盘 IO”转化为“内存 IO”,覆盖数据页和索引页的读写,加速逻辑分读写两类:

1. 加速读操作:避免重复磁盘读

  • 读操作的瓶颈是“磁盘随机读”,Buffer Pool 通过「缓存复用+预读」解决:
  • 缓存命中优先:查询时先检查 Buffer Pool 中是否存在目标页(数据页/索引页,按“页号”匹配),命中则直接读内存,跳过磁盘 IO;未命中则从磁盘加载该页到 Buffer Pool,后续同页查询可复用。
  • 预读减少后续 IO:通过“线性预读”(连续访问某区多页时预读该区剩余页)、“随机预读”(某区13+页被缓存时预读全区),提前加载可能需要的页,避免后续查询再触发磁盘 IO。

2. 加速写操作:延迟磁盘写+批量刷盘

  • 写操作的瓶颈是“磁盘随机写”,Buffer Pool 通过「脏页暂存+后台刷盘」优化:
  • 先改内存,不立即写磁盘:更新/插入时,先加载目标页到 Buffer Pool,修改内存页(标记为“脏页”,即内存与磁盘数据不一致),仅记录 redo log 确保安全后就返回,避免每次写都触发磁盘 IO。
  • 后台批量刷盘:专门线程在“空闲时”或“脏页达阈值”时,将 Buffer Pool 中的脏页批量刷回磁盘,把“零散写”合并为“批量写”,减少磁盘寻道时间(磁盘擅长连续写)。

二、Change Buffer:通过“索引写缓冲”加速非唯一二级索引写

Change Buffer 是 Buffer Pool 的“子集”,仅针对「非唯一二级索引页」的写操作优化——核心解决“二级索引页未缓存时,避免频繁加载磁盘页”的问题:

1. 适用场景:仅非唯一二级索引

唯一索引(如主键、唯一键)写操作时,必须校验唯一性,需先加载索引页到 Buffer Pool,无法用 Change Buffer;而非唯一二级索引无需唯一性校验,可借助 Change Buffer 延迟写。

2. 加速逻辑:先缓冲写操作,合并后再刷盘

  • 当更新/插入涉及“非唯一二级索引”,且目标索引页未在 Buffer Pool 中时:
  • 不直接从磁盘加载索引页,而是将“索引修改操作”(如插入一条索引记录的信息)暂存到 Change Buffer 中,操作立即返回,避免一次不必要的磁盘读(加载索引页)。
  • 后续当该索引页被“读操作加载到 Buffer Pool”,或后台线程触发合并时,再将 Change Buffer 中暂存的修改“合并”到索引页,最后随索引页一起批量刷回磁盘。

3. 核心价值:减少“索引写”的磁盘 IO

非唯一二级索引写场景(如高频插入带二级索引的表)中,若每次写都加载磁盘索引页,会产生大量磁盘读;Change Buffer 通过“缓冲操作+合并执行”,将“多次零散的索引页加载+修改”合并为“一次加载+批量修改”,大幅减少磁盘 IO 次数。

三、二者协作:互补优化读写性能

读操作:主要依赖 Buffer Pool 缓存数据页/索引页,Change Buffer 无直接作用(仅合并时需加载索引页)。

写操作:

写“数据页/唯一索引页”:靠 Buffer Pool 的脏页机制延迟刷盘;

写“非唯一二级索引页”:先靠 Change Buffer 缓冲操作,再合并到 Buffer Pool 的索引页,最后随脏页批量刷盘。

结论

  • Buffer Pool 是基础:通过缓存“数据页/索引页”,覆盖通用读写,用内存 IO 替代磁盘 IO,同时通过批量刷盘优化写操作。
  • Change Buffer 是补充:仅优化“非唯一二级索引写”,通过缓冲写操作避免频繁加载磁盘索引页,减少写操作的磁盘 IO 成本。
  • 二者共同作用,从“通用缓存”和“索引写专项优化”两个维度,最大化降低磁盘 IO 开销,提升 MySQL 读写速度。