Skip to content
进阶

一句话答案

Buffer Pool 是 InnoDB 的内存缓冲池,缓存数据页,用改进的 LRU(young/old 分区)防止全表扫描冲刷热数据。

核心要点

MVCC(Multi-Version Concurrency Control,多版本并发控制):

核心思想:不加锁,通过保存数据的多个历史版本,让读操作读历史快照,写操作创建新版本,读写不互相阻塞。

MVCC 的三个核心组件:

1. 隐藏列(每行数据都有)

每行数据隐含三个字段:
  DB_TRX_ID(6字节):最近修改本行的事务 ID
  DB_ROLL_PTR(7字节):回滚指针,指向 undo log 中的上一个版本
  DB_ROW_ID(6字节,可选):隐藏主键(无主键时使用)

2. undo log(版本链)

每次修改一行,都会在 undo log 中记录旧版本,通过 DB_ROLL_PTR 串成版本链:

当前版本(事务100)→ 上一版本(事务80)→ 再上一版本(事务60)→ ...

3. Read View(读视图)

Read View 在快照读时创建,包含:
  creator_trx_id:创建 Read View 的当前事务 ID
  trx_ids:创建时所有活跃(未提交)事务的 ID 集合
  min_trx_id:trx_ids 中最小的事务 ID
  max_trx_id:下一个将被分配的事务 ID(即当前最大事务ID + 1)

可见性判断规则(判断某版本对当前事务是否可见):

对于版本链中某个版本的 DB_TRX_ID(设为 trx_id):

1. trx_id == creator_trx_id → 自己修改的,可见
2. trx_id < min_trx_id → 该事务在 Read View 创建前已提交,可见
3. trx_id >= max_trx_id → 该事务在 Read View 创建后才开始,不可见
4. min_trx_id <= trx_id < max_trx_id:
   └─ trx_id 在 trx_ids 中 → 该事务创建时还未提交,不可见
   └─ trx_id 不在 trx_ids 中 → 该事务已提交,可见

如果当前版本不可见 → 沿 DB_ROLL_PTR 找上一个版本,重复判断

READ COMMITTED vs REPEATABLE READ 的区别(Read View 生成时机):

隔离级别Read View 生成时机
READ COMMITTED每次快照读都生成新的 Read View → 能看到其他事务已提交的新数据 → 不可重复读
REPEATABLE READ整个事务只在第一次快照读时生成一次 Read View → 后续读都用同一个 → 可重复读

如何解决脏读:

  • undo log 版本链中,未提交事务的修改,其 trx_id 在当前 Read View 的 trx_ids 中
  • 根据可见性规则,未提交版本不可见 → 读到的是更早的已提交版本 → 脏读被解决
追问与易错

追问方向:

  • 为什么用改进 LRU?
  • Buffer Pool 大小怎么设?
  • 多实例有什么好处?

易错点:

  • ❌ Buffer Pool 越大越好——要留给 OS 和其他进程
  • ❌ 混淆 Buffer Pool 和 OS Page Cache

💡 记忆锚点

Buffer Pool 是 InnoDB 的"内存书架":常用的数据页放在书架上避免反复去仓库(磁盘)取。改进 LRU 把书架分成热区和冷区——新来的书先放冷区观察,被多次翻阅才提升到热区,防止一次全表扫描把热门数据全挤下架。