Skip to content

P24 Mysql 引擎层 BufferPool 工作过程原理 ​

面试题:InnoDB 的 Buffer Pool 是什么?一次查询/更新在 Buffer Pool 里是怎么工作的?

1. Buffer Pool 是什么 ​

InnoDB 在内存里维护的一块缓存区域(默认 128MB,通常配置为物理内存的 60%~70%),缓存数据页(16KB)和索引页,避免每次读写都走磁盘。

text
读:先看 Buffer Pool,命中直接返回;未命中再从磁盘加载进 Buffer Pool
写:先改 Buffer Pool 里的页(脏页),后台异步刷盘

2. 读数据的过程 ​

text
SQL → 定位索引页 → 检查 Buffer Pool 是否有该页
 ├─ 命中:直接读内存页返回
 └─ 未命中:从磁盘读页 → 放入 Buffer Pool(按 LRU 淘汰)→ 返回

3. 写数据的过程(关键:先改内存,异步刷盘) ​

text
UPDATE 某行
 → 行所在数据页在 Buffer Pool 中(不在则先加载)
 → 修改内存中的页(变成脏页)
 → 写 redo log(记录"改了什么",保证崩溃可恢复)
 → 事务提交
 → 后台线程(Master/刷盘线程)在适当时机把脏页刷回磁盘

这就是WAL(Write-Ahead Logging):先写日志、后刷数据页,保证性能和数据安全。

4. 页面淘汰:LRU 与改良 ​

InnoDB 用 LRU(最近最少使用) 管理页,并做了改良:

  • 链表分成**新生代(young)和旧生代(old)**两段;
  • 新读入的页先进 old 区,被再次访问才晋升 young 区;
  • 防止"一次大范围扫描"把热数据全部挤出内存(缓冲池污染)。

配置:innodb_buffer_pool_size、innodb_old_blocks_time。

5. 相关概念 ​

  • 脏页:内存中被修改、还没刷盘的页;
  • Free List / LRU List / Flush List:空闲页链表、LRU 链表、待刷盘脏页链表;
  • Change Buffer(写缓冲):对非唯一二级索引的插入/更新先缓冲,减少随机 IO;
  • doublewrite buffer:刷盘前先写双写缓冲,防止页半写损坏。

加分点 ​

  • 为什么 Buffer Pool 要大:命中率越高,磁盘 IO 越少;show engine innodb status 可看命中率;
  • 多个 Buffer Pool 实例(innodb_buffer_pool_instances)减少并发锁竞争;
  • 追问"重启后缓存丢失怎么办":冷启动后命中率低,可用预热(如 SELECT ... 扫描热点页)。

一句话总结 ​

Buffer Pool 是 InnoDB 的内存页缓存:读命中内存、未命中才读磁盘;写则先改内存页并记 redo log(WAL),后台异步刷盘;用改良 LRU 淘汰页,配合 Change Buffer、doublewrite 等机制兼顾性能与安全。

基于 VitePress 重建