SQL Buffer Pool 是通过内存缓存数据页并异步刷盘来减少磁盘I/O的核心机制:命中则直接内存操作,未命中则从磁盘加载至Free链表;写操作先改内存页并记redo/undo,标记脏页入Flush链表;由LRU链表管理热度、Free链表分配空页、Flush链表驱动多时机异步刷脏。

SQL Buffer Pool 的工作机制,核心是用内存“挡”住磁盘,让读写操作尽量在内存中完成,再通过异步、延迟、分批的方式把变更落盘。它不是简单缓存,而是一套有状态、有链表、有策略的内存管理子系统。
Buffer Pool 怎么加载数据页
当 SQL 需要访问某行数据,InnoDB 会先查 Buffer Pool 是否已有对应的数据页(16KB):
- 命中:直接从内存读取或修改,不碰磁盘
- 未命中:从磁盘(.ibd 文件)读取整页 → 找一个空闲缓存页(Free 链表)→ 把页内容载入 → 更新页元信息(表空间 ID、页号、访问时间等)
- 若 Free 链表为空,则触发 LRU 淘汰机制,腾出空间
Buffer Pool 怎么处理写操作
所有 DML(INSERT/UPDATE/DELETE)都先改内存页,不直写磁盘:
- 修改前,把旧值写入 undo log(用于回滚和 MVCC)
- 修改 Buffer Pool 中的页,并标记为“脏页”(dirty page)
- 同步写入 redo log(顺序写,保证崩溃可恢复),但不立即刷脏页
- 事务提交时,只要 redo log 持久化成功,就认为事务已提交
Buffer Pool 怎么管理缓存页生命周期
InnoDB 用三类链表协同管理页的状态与去留:
- Free 链表:记录当前未被使用的空闲页,分配新页时从此取
- LRU 链表:按访问热度组织,分为新生代(热数据)和老生代(冷数据)。默认只把满足“被访问 + 在老生代停留超时(innodb_old_blocks_time)”的页提升到新生代头部,防预读污染
- Flush 链表:专门挂载所有脏页。后台线程(如 Page Cleaner)定期从中挑页刷盘,刷完即从 Flush 链表移除,但仍在 LRU 链表中(变为干净页)
Buffer Pool 怎么刷脏页到磁盘
刷脏不是等事务结束才做,而是多时机、异步进行:
- Buffer Pool 空间紧张时:淘汰脏页前必须先刷盘
- 后台线程定期扫描 Flush 链表:按脏页生成时间、修改量、IO 压力动态调度
- 系统空闲期:主动推进刷脏,避免高峰堆积
- 检查点(checkpoint)触发:确保 redo log 可循环复用,强制刷掉部分老脏页
刷脏过程本身也受控:一次只刷一批页,避免瞬时 I/O 尖峰;支持 IO 能力自适应(如 innodb_io_capacity 参数)。










