知识卡片
多版本并发控制(MVCC)的版本序列机制
内容
锁机制和时间戳机制都面临一个共同的困境:一旦发现读写冲突,要么 等待(锁)要么回滚重启(时间戳),本质上是”读”和”写”互相阻挡对方。 MVCC换了一个思路彻底避开这个冲突:不让写操作覆盖旧值,而是给每个 数据对象保留一整条版本序列,每次写入都生成一个带时间戳的新版本, 旧版本依然保留。读操作不再需要跟并发的写操作互相协调——它只需要 从这条版本序列里,找到时间戳小于自己、但在所有符合这个条件的版本 里时间戳最大的那一个(也就是”在我看来最新的、但确实早于我开始 的版本”),直接读取即可,完全不用理会有没有更晚的事务正在写这个 数据。这样一来,读操作和写操作天然不会互相阻塞——因为它们操作的 根本不是同一份数据,而是各自看到不同版本的快照。代价也很明显: 每个数据对象都要维护多份历史版本,存储空间开销比单版本大得多, 需要额外的策略定期清理确认不再有事务需要的旧版本;而且一个事务 提交时,它对数据库造成的”最终影响”在提交那一刻并不能立即确定 (因为可能还有更年轻的事务正在读它写之前的旧版本)。因此MVCC 在实践中很少单独使用,常常与其他并发控制方法(如时间戳)结合, 用MVCC消除读写冲突、用时间戳规则处理写写冲突。
参考来源
- 位置:《数据库原理(微课版)》第11章《事务处理技术》11.3.4节"多版本
并发控制"(源文件:_epub-src/index_split_007.html)
- 结论依据:原文明确"系统为每个数据Q的值保存一个版本序列,在事务
需要写数据Q时添加一个新版本,事务需要读数据时,读取比自己的
时间戳小且具有最大时间戳值的事务写入的版本,从而保障调度的正确性
……数据多版本存储需要的空间比较大,需要采用策略删除大量的无效
版本。另外,在提交一个事务时无法立即确定其对数据库的影响……
它常常与其他并发控制方法结合使用,例如Oracle、Kingbase ES等
数据库中都采用了多版本与时间戳相结合的并发控制方法",因此可以
推出MVCC通过版本序列消除读写冲突及其存储/确定性代价。
- 原始内容:系统为每个数据Q的值保存一个版本序列,在事务需要写数据
Q时添加一个新版本,事务需要读数据时,读取比自己的时间戳小且具有
最大时间戳值的事务写入的版本,从而保障调度的正确性。