← [ BACK_TO_NOTES ]

MVCC

MVCC 通过维护数据的多个版本与一致性快照,让数据库在很多场景下兼顾并发读取能力和事务隔离。

#concept #growing #backend #database

[!info] related notes

MVCC

一句话定义

MVCC 是数据库通过维护同一行数据的多个版本和一致性快照,让读写在很多场景下不必彼此阻塞的并发控制机制。

它要解决什么问题

如果数据库只有“当前最新值”这一份数据,那么会很麻烦:

  • 写事务刚改完但还没提交,读事务到底能不能看
  • 读事务正在扫描大量数据时,写事务是不是都得等它结束
  • 想让同一个事务里多次读取看到稳定结果时,旧值从哪里来

MVCC 的目标就是:

  • 让读操作尽量不挡写
  • 让写操作尽量不因为普通读而停住
  • 让事务能根据自己的快照读到“它应该看到的版本”

核心机制 / 工作原理

1. 关键思想不是“改值”,而是“管理版本”

MVCC 的核心思路是:

  • 一条记录在逻辑上不只有一个值
  • 不同事务在不同时间点,可能各自看到不同版本

所以数据库不只是问“最新值是什么”,还要问:

  • 这个版本是谁写的
  • 这个写事务是否已提交
  • 当前读事务能不能看到它

2. 读事务通常基于某个一致性快照

很多实现里,事务在开始或第一次一致性读取时,会形成一个“可见性视图”。

之后它读取某一行时,数据库会判断:

  • 最新版本是否对当前事务可见
  • 如果不可见,是否需要回退到更旧的版本

这也是为什么同一事务里,即使其他事务已经提交了更新,你仍可能继续看到旧值。

3. 写事务不是把 MVCC 变成“无锁世界”

MVCC 主要改善的是读写冲突,不是取消一切协调。

通常仍然需要:

  • 用锁处理写写冲突
  • 防止两个事务同时改同一行导致覆盖
  • 在范围更新、结构变更或更强隔离级别下继续配合锁

所以更准确的说法是:

  • MVCC 降低了很多不必要的读写阻塞
  • 但它从不意味着“数据库不需要锁”

4. 旧版本通常离不开日志或版本链路

事务之所以能读到旧版本,不是凭空得到一份历史快照,而是数据库维护了相应的版本信息。

常见思路包括:

  • InnoDB 倾向于借助 Undo Log 还原旧版本
  • PostgreSQL 倾向于直接利用行版本和事务可见性信息判断是否可见

这也是为什么 MVCC 往往和日志、回收、清理机制紧密耦合。

最小例子 / 最小场景

事务 A 在更新一条订单状态,但还没提交时:

  • 事务 B 如果只是普通读取,通常仍能看到旧版本
  • 事务 B 不必一定因为 A 正在写而整条查询都停住
  • A 提交后,新开启的事务更可能看到新版本

这样数据库在高并发下更容易同时服务读取和写入。

从原理上最该抓住哪几层

1. MVCC 的核心不是“存多个值”,而是“定义版本可见性”

只有“旧版本存在”还不够,更关键的是:

  • 当前事务能看到哪个版本
  • 为什么能看到它
  • 什么时候这个旧版本可以被回收

2. MVCC 提升的是读写并发,不是无限并发

它最擅长的是:

  • 普通读和写同时存在时,减少彼此等待

它不擅长替代:

  • 写写冲突控制
  • 死锁处理
  • 所有更高隔离需求

3. MVCC 往往把问题从“阻塞”转移到“版本管理”

好处是:

  • 读操作更顺滑

代价是:

  • 需要维护版本链
  • 需要清理旧版本
  • 长事务会拖慢版本回收

这也是为什么长事务在 MVCC 系统里经常是性能与空间上的麻烦制造者。

边界与易混淆点

  • MVCC 不是“完全不用锁”。写写冲突、元数据变更和某些隔离级别下仍然需要锁。
  • MVCC 不是所有数据库都以同样方式实现,理解差异时要回到具体产品。
  • MVCC 解决的是一部分并发可见性问题,不等于自动解决所有幻读、死锁和一致性问题。
  • MVCC 也不是“谁都能永远看到旧版本”。旧版本的保存和回收都受事务生命周期约束。

学习检查

不看正文回答:

  1. MVCC 的核心为什么不是“存很多副本”,而是“定义版本可见性”?
  2. Snapshot 在一次读取中解决什么一致性问题?
  3. 为什么 MVCC 可以减少很多读写阻塞,却不能消灭写写冲突和锁?
  4. 长事务为什么会拖延旧版本回收并造成空间/性能问题?
  5. Undo-based 与 tuple-version-based 实现可以不同,但它们共同必须解决哪些问题?
  6. 隔离级别与 MVCC 可见性规则是什么关系?
  7. 给两个并发事务读写同一行的场景,说明它们分别可能看到哪个版本以及何时冲突。
创建于 2026/5/3 更新于 2026/9/30
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本