MVCC 是什么
MVCC(多版本并发控制)通过保存数据的历史版本让读操作不阻塞写、写不阻塞读:每个事务看到的是某个时间点的可见版本,旧版本由撤销日志或旧行保留,由后台机制清理。不同隔离级别对应不同的快照规则,因此同一份数据在不同事务中可能看到不同内容。它的主要代价是版本堆积与清理压力,长事务与热点更新是常见诱因。
基本信息
| 核心机制 | 每个事务看到某一时间点的可见版本,旧版本保留供并发读 |
|---|---|
| 典型实现 | PostgreSQL 的行版本与 VACUUM;InnoDB 的 undo log 与 purge |
| 运维关注 | 长事务、快照过老、清理滞后导致空间膨胀 |
| 读写关系 | 普通读不加锁,写与写之间仍需要锁或冲突检测 |
| 代价 | 存储与清理开销上升,复制与备份需考虑版本信息 |
常见现象与对策
| 现象 | 原因 | 对策 |
|---|---|---|
| 表空间持续增长 | 旧版本未被及时清理 | 排查长事务,检查清理参数与调度 |
| 查询返回旧数据 | 事务快照建立较早 | 缩短事务范围,避免事务中等待用户输入 |
| 更新热点行失败 | 写写冲突或锁等待超时 | 缩短持有时间,考虑拆分行或异步化 |
| 清理进度落后 | 长事务阻塞回收 | 设置事务超时,监控最老快照年龄 |
典型使用场景
- 高并发读场景:读请求不阻塞写入,吞吐显著提升
- 报表与导出:需要在一致快照上运行较长时间的查询
- 长事务治理:识别并限制长时间持有快照的事务
- 数据库调优:分析空间膨胀与清理滞后的根因
- 并发问题排查:理解同一行在不同事务中为何看到不同值
- 架构评审:判断业务是否依赖“读到最新值”,据此选择隔离级别
MVCC 解决的是读写冲突,不解决写写冲突:同一行并发更新仍需要锁、乐观锁版本号或条件更新来保证正确性。
长事务持有老快照会让清理机制无法推进,表与索引持续膨胀,最终影响整个实例的性能。