作者:瀚高PG实验室 (Highgo PG Lab)

Multiversion Concurrency Control (MVCC)让PostgreSQL具有即使在数量庞大的数据库读写活动过程中也能提供高并发性的能力。

PostgreSQL使用事务ID,来实现MVCC。事务ID可以通过txid_current()函数获得。每个事务都会看到当前事务启动之前的所有已开启的以及已提交的事务的影响。

如果隔离级别是提交读取(read committed),那么快照是在每条SQL语句开始的时候被记录的。而如果隔离级别为序列化(serializable),快照则会在事务开始时被记录。

每当一个快照被记录,以下信息会被获取:

    已被提交的ID最大的事务。

    正在执行的事务的ID。

通过这些信息,PostgreSQL就可以判定一个事务的活动是否对一个正在执行的语句可见。

PostgreSQL中用于生成数据快照的两个最相关的系统列为:

    xmin:创建特定行的事务。通过INSERT和UPDATE设置。

    xmax:删除特定行的事务。通过DELETE和UPDATE设置。

我们分别来看一下执行INSERT、DELETE和UPDATE时的结果。以下所有操作中,事务的隔离级别都为提交读取(read committed)。

INSERT

pgsql gemo扩展 pgsql mvcc_数据库

图1 插入操作

如图1所示,我们在一个事务中创建表mvcctst,插入数据,查询后发现xmin列被填充而xmax列未被填充,因为该事务并未删除记录。xmin列的值与当前事务ID相同。

DELETE




pgsql gemo扩展 pgsql mvcc_隔离级别_02


图2 删除操作


然后我们在事务中从表mvcctst中删除记录,如图2所示。

pgsql gemo扩展 pgsql mvcc_隔离级别_03

图3 另一个会话

然后打开另一个会话,图3显示了查询结果。我们可以看到,依然能够显示已经删除的那条记录。

再回到第一个会话中,可以看到事务ID为11776。



pgsql gemo扩展 pgsql mvcc_数据库_04


图4 回到第一个会话


UPDATE



pgsql gemo扩展 pgsql mvcc_pgsql gemo扩展_05


图5 更新操作


如图5所示,我们在事务中修改了表mvcctst中name列的值。

打开另一个会话,查询后发现name列中记录的是更新前的值。

pgsql gemo扩展 pgsql mvcc_数据库_06

图6 另一个会话

回到第一个会话中(见图5),看到新版本的记录是由事务ID 11778创建的。