04-MVCC
type
status
date
slug
summary
tags
category
icon
password
MySQL中的MVCC(Multi-Version Concurrency Control,多版本并发控制)是InnoDB存储引擎实现高并发和事务隔离的核心机制,它依赖于Undo Log和隐藏列版本控制,避免了大量加锁导致的性能问题。
1️⃣ MVCC 工作原理
- InnoDB 为每一行记录维护两个隐藏列
列名 | 说明 |
trx_id | 最后一次修改该行的事务 ID |
roll_pointer | 指向 undo log 中的历史版本(旧值)地址 |
- Undo Log(回滚日志)
当事务对记录进行
UPDATE
/DELETE
时,InnoDB 会将旧版本写入 Undo Log,并通过roll_pointer
链接旧数据版本,形成版本链。
2️⃣ 快照读 vs 当前读
类型 | 使用方式 | 是否加锁 | 是否使用 MVCC | 说明 |
快照读(Snapshot Read) | 普通 SELECT | ❌ | ✅ | 读取数据的历史版本 |
当前读(Current Read) | SELECT ... FOR UPDATE / UPDATE / DELETE | ✅ | ❌ | 读取的是当前最新版本数据并加锁 |
3️⃣ MVCC 可见性判断规则
条件 | 描述 |
记录的trx_id < 当前事务id | 说明这条记录是其他事务创建的 |
创建该版本的事务已经 提交 | 说明这条记录对当前事务可见 |
修改该版本的事务在当前事务启动后提交的 | 不可见(会通过 roll_pointer 继续向下找旧版本) |
4️⃣ 不同隔离级别下 MVCC 的使用
隔离级别 | 使用 MVCC | 行为说明 |
READ UNCOMMITTED | ❌ | 直接读最新数据,甚至未提交(脏读) |
READ COMMITTED | ✅ | 每次读创建新的快照(不可重复读) |
REPEATABLE READ(默认) | ✅ | 整个事务中快照固定(防止不可重复读) |
SERIALIZABLE | ❌ | 所有读都加锁,MVCC 不使用 |
5️⃣ MVCC 局限与注意点
限制 | 说明 |
当前读不使用 MVCC | 如 SELECT FOR UPDATE 必须加锁 |
DELETE/UPDATE 会生成新版本 | 并记录旧版本到 Undo Log |
Undo Log 会增长 | 如果长事务不提交,会导致 Undo Log 积压 |
并不解决幻读 | 幻读通过 间隙锁(Gap Lock) 解决 |
6️⃣ Buffer Pool
Buffer Pool 是 InnoDB 引擎的内存缓存区域,用于缓存以下类型的数据页:
类型 | 说明 |
数据页(Data Pages) | 表记录页,最常用 |
索引页(Index Pages) | B+ 树结构的内部节点或叶子节点 |
Undo 页 | 回滚段中的页 |
插入缓冲页(Change Buffer) | 二级索引的延迟更新页 |
系统页 / 字典页 | 系统表空间的元数据页 |
自适应哈希索引(AHI) | 查询热点页动态构建的哈希索引 |
- Buffer Pool 是由一组 页(Page) 组成,每页固定大小
16KB
,可以设置 Buffer Pool 总容量(默认一个实例):
组成部分 | 说明 |
LRU 链表 | 最近最少使用(Least Recently Used)淘汰机制 |
Free List | 空闲页,等待分配 |
Flush List | 脏页列表,等待刷新到磁盘(刷盘) |
1.SQL 执行时的 Buffer Pool 交互机制
- 🔁 读操作(SELECT)
- 查询数据 → InnoDB 查看数据页是否在 Buffer Pool 中(称为 Buffer Pool 命中)
- 若命中,则直接从内存返回数据(快速)
- 若未命中(Buffer Pool Miss):
- 触发物理 IO,从磁盘加载页到 Buffer Pool
- 若内存已满,则通过 LRU 淘汰冷数据页
查询路径称为:逻辑读 → 物理读
- 🔁 写操作(INSERT / UPDATE / DELETE)
- 修改的数据页先在 Buffer Pool 中更新 → 页变为“脏页”
- 同时写入 Undo Log(用于回滚)和 Redo Log(用于崩溃恢复)
- 不立即写磁盘,后台线程异步刷新脏页(checkpoint)
✅ 这是 WAL(Write-Ahead Logging)机制 的体现:先写日志,再写磁盘,保证事务一致性。
2.Buffer Pool 的 LRU 淘汰策略(热数据优先)
- 双端 LRU 链表:
- 新加载页默认插入到 LRU 的中部(约 5/8 位置),防止全表扫描挤掉热点页
- 热点页频繁访问将靠近头部,保留时间更长
[young区域] ←———→ [old区域]
↑ ↑
最近使用 最久未用
- 该策略可通过:
控制全表扫描对缓存污染的影响。
3.脏页刷盘机制(Checkpoint)
Buffer Pool 中的脏页不能无限堆积,必须定期刷到磁盘:
刷盘触发方式 | 说明 |
后台线程(默认) | 每秒/后台周期性写盘 |
事务提交 | 若启用 innodb_flush_log_at_trx_commit=1 则强制刷日志 |
Redo Log 满了 | 强制刷脏页释放空间 |
Buffer Pool 满了 | 淘汰页时需将脏页先写盘 |
4.性能相关参数(重点)
参数名 | 描述 |
innodb_buffer_pool_size | ✅ 核心参数,设置 Buffer Pool 总容量,推荐为系统内存的 70%-80%(专用数据库) |
innodb_buffer_pool_instances | Buffer Pool 分片个数,提升并发(建议 ≥ 1G 内存时设置为 2、4、8) |
innodb_flush_method | 控制刷盘方式,常见: O_DIRECT 避免双缓存 |
innodb_flush_log_at_trx_commit | 控制日志刷新时机,影响事务安全性与性能 |
innodb_lru_scan_depth | LRU 每次扫描深度,影响淘汰效率 |
上一篇
03-事务隔离级别与锁机制
下一篇
01-数学
Loading...