PostgreSQL如何判断事务新旧

PostgreSQL由于其多版本特性,经常需要去比较两个事务的新旧。

那么该如何比较两个事务的新旧关系呢?你可能会说通过XID(事务ID)不就可以了,没错!例如一个事务ID是1000000,另一个事务ID是1000001,那么显然是1000000的事务更旧。

但是通过事务ID去判断远不止这么简单,我们都知道pg中的事务ID是用32位无符号数来表示的,也就是说如果不引入特殊的处理,当PostgreSQL的XID 到达40亿,会造成溢出,从而新的XID 为0。

而按照PostgreSQL的MVCC 机制实现,之前的事务就可以看到这个新事务创建的元组,而新事务不能看到之前事务创建的元组,这违反了事务的可见性。这种现象称为XID 的回卷问题。

因此我们比较XID还必须要考虑到回卷的情况。

首先我们需要知道在PG中0,1,2这三个XID的特殊含义:

  • InvalidTransactionId = 0:表示是无效的事务ID
  • BootstrapTransactionId = 1:表示系统表初使化时的事务ID,比任务普通的事务ID都旧。
  • FrozenTransactionId = 2:冻结的事务ID,比任务普通的事务ID都旧。

我们看看PG中是如何比较的:
在这里插入图片描述

上面的代码中if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))表示当两个XID中有一个不是普通的XID时,那么比较结果直接返回id1 < id2,因为特殊的XID和普通的XID相比,一定是特殊的XID更旧。

而对于都是普通的XID的情况,pg中使用(int32) (id1 - id2),将比较结果转为32位整数。这样做是什么意思呢?

打个比方,如果发生了XID 回卷后,即使id1=4294967290比id2=5(回卷后的XID)大,但因为相减后diff大于2^31,结果值转成int32后会变成一个负数,从而让判断逻辑与事务回卷前都是一样的: (int32)(id1 - id2) < 0。

从而我们可以得出结论:

1. 特殊的事务ID一定比普通的事务ID更旧;
2. 对于都是普通事务ID的情况,PostgreSQL中是使用2^31取模的方法来进行事务的比较。

参考:
src/backend/access/transam/transam.c

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值