MySQL 的 MVCC(Multi-Version Concurrency Control,多版本并发控制)是实现高性能、高并发事务的核心机制,尤其在可重复读(REPEATABLE READ)隔离级别下发挥重要作用。以下是 MVCC 的详细解析:
1. MVCC 的核心概念
(1)多版本共存
MVCC 为数据库中的每行记录保存多个历史版本,每个事务读取时会看到特定版本的数据,而非最新数据。这使得读操作无需加锁,提高了并发性能。
(2)隐藏字段
InnoDB 为每行记录添加三个隐藏字段:
DB_TRX_ID:记录最后一次修改该行的事务 ID。DB_ROLL_PTR:指向回滚段(Rollback Segment)中的undo日志,用于生成旧版本数据。DB_ROW_ID:行ID,若表无主键或唯一非空索引时自动生成。
(3)事务ID
每次启动事务时,InnoDB 分配一个唯一递增的事务 ID(trx_id),用于标识事务的先后顺序。
2. MVCC 的工作原理
(1)版本链与 Undo 日志
- 版本链:每行记录的多个版本通过
DB_ROLL_PTR连接成链表,最新版本指向最早版本。 - Undo 日志:记录每行记录的历史版本,用于回滚和生成一致性视图。
(2)一致性视图(Read View)
每个事务启动时,InnoDB 会创建一个一致性视图,包含以下内容:
trx_ids:当前活跃事务的 ID 列表(未提交的事务)。low_limit_id:当前最大事务 ID + 1(未来可能分配的最小 ID)。up_limit_id:trx_ids中的最小事务 ID。
(3)可见性规则
当事务读取某行记录时,MVCC 根据以下规则判断版本是否可见:
- 若记录的
DB_TRX_ID < up_limit_id:事务启动前已提交,可见。 - 若
DB_TRX_ID ≥ low_limit_id:事务启动后生成,不可见。 - 若
up_limit_id ≤ DB_TRX_ID < low_limit_id:- 若
DB_TRX_ID在trx_ids中:事务未提交,不可见。 - 否则:事务已提交,可见。
- 若
3. MVCC 在不同隔离级别下的行为
(1)读已提交(READ COMMITTED)
- 一致性视图:每个
SELECT语句执行时重新生成。 - 效果:只能读取已提交的数据,可能读到其他事务的更新(不可重复读)。
(2)可重复读(REPEATABLE READ)
- 一致性视图:事务启动时生成一次,整个事务期间复用。
- 效果:同一事务中多次读取相同记录结果一致,避免不可重复读和普通查询的幻读。
(3)串行化(SERIALIZABLE)
- MVCC 失效:所有
SELECT变为当前读(加共享锁),强制事务串行执行。
4. MVCC 与当前读的区别
| 操作类型 | 读取方式 | 是否加锁 | 可见性规则 |
|---|---|---|---|
普通 SELECT | 快照读(MVCC) | 否 | 遵循一致性视图规则 |
SELECT ... FOR UPDATE | 当前读(最新数据) | 是(行锁/间隙锁) | 读取最新版本,无视视图规则 |
INSERT/UPDATE/DELETE | 当前读(最新数据) | 是(行锁/间隙锁) | 读取最新版本并加锁 |
5. MVCC 如何避免幻读?
在可重复读隔离级别下:
-
普通查询(MVCC):
事务始终使用启动时的一致性视图,即使其他事务插入新记录,当前事务也看不到(因为新记录的DB_TRX_ID大于视图的low_limit_id)。 -
当前读(如
SELECT ... FOR UPDATE):
通过间隙锁(Gap Lock)锁定记录之间的间隙,阻止其他事务插入新记录,从而避免幻读。
6. MVCC 的局限性与优化
(1)局限性
- 长事务:长时间运行的事务会保留大量 Undo 日志,占用存储空间。
- 锁竞争:当前读操作仍需加锁,可能导致死锁或性能下降。
(2)优化建议
- 避免长事务:缩短事务执行时间,减少 MVCC 维护的版本数量。
- 合理使用索引:确保当前读操作通过索引加锁,减小锁粒度。
- 监控 Undo 日志:定期清理无用的 Undo 日志(通过
innodb_purge_threads参数控制)。
7. 总结
MVCC 通过多版本共存和一致性视图,在不加锁的情况下实现了事务的隔离性,显著提高了并发性能。其核心优势在于:
- 读-写不冲突:读操作无需等待写锁,反之亦然。
- 事务隔离:在可重复读级别下,避免不可重复读和普通查询的幻读。
但 MVCC 仅适用于普通查询(快照读),对于当前读(如 INSERT、UPDATE)仍需依赖锁机制来保证数据一致性。
842



被折叠的 条评论
为什么被折叠?



