任何数据库的主要要求之一就是实现可伸缩性。只有将争用(锁定)最小化(如果不能一起删除),才可以实现。由于读/写/更新/删除是数据库中发生的一些主要的频繁操作,因此对于这些操作并发进行而不被阻塞非常重要。为了实现这一目标,大多数主要数据库都采用了一种称为多版本并发控制的并发模型,该模型将争用降低到最低限度。
什么是MVCC
多版本并发控制(以下简称MVCC)是一种算法,可通过维护同一对象的多个版本来提供精细的并发控制,以使READ和WRITE操作不会冲突。这里的WRITE表示UPDATE和DELETE,因为无论如何新插入的记录都将按照隔离级别受到保护。每个WRITE操作都会生成对象的新版本,并且每个并发读取操作都会根据隔离级别读取对象的不同版本。由于读取和写入操作均在同一对象的不同版本上进行,因此这些操作都不需要完全锁定,因此两者都可以并发操作。争用仍然存在的唯一情况是当两个并发事务尝试写入同一记录时。
当前大多数主要数据库都支持MVCC。该算法的目的是维护同一对象的多个版本,因此MVCC的实现因数据库而异,仅在创建和维护多个版本方面有所不同。因此,相应的数据库操作和数据存储发生了变化。
公认的实现MVCC的方法是PostgreSQL和Firebird / Interbase使用的一种,而InnoDB和Oracle使用的另一种。在随后的章节中,我们将详细讨论如何在PostgreSQL和InnoDB中实现它。
PostgreSQL中的MVCC
为了支持多个版本,PostgreSQL维护每个对象的其他字段(PostgreSQL术语为Tuple),如下所述:
- xmin –插入或更新元组的交易的交易ID。如果是UPDATE,则将使用此事务ID分配更新版本的元组。
- xmax –删除或更新元组的交易的交易ID。如果是UPDATE,则为元组的当前现有版本分配此事务ID。在新创建的元组上,此字段的默认值为null。
PostgreSQL将所有数据存储在称为HEAP的主存储中(页面的默认大小为8KB)。所有新元组都将xmin作为创建它的事务进行处理,而旧版本元组(已更新或删除)将分配给xmax。从旧版本元组到新版本始终存在链接。在隔离的情况下,较旧版本的元组可用于在回滚的情况下重新创建元组,并可通过READ语句读取较旧版本的元组。
考虑到表有两个元组,T1(值1)和T2(值2),可以在下面的3个步骤中演示新行的创建: