SQL Buffer Pool 的工作机制

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 参数)。