The PostgreSQL wiki建议实现使用重试循环的UPSERT的方法。此解决方案中隐含的是使用“子事务ID”。在维基文章中有以下警告:
正确的解决方案使用缓慢且笨拙,不适合大量数据。它还可能会烧掉大量的子事务ID - 避免刻录XID是当前“PostgreSQL中的本机UPSERT”工作的明确目标。
使用“大量子事务ID”的后果是什么?我真的不知道子事务ID是什么 - 这只是一种对嵌套事务进行编号的方式,这是否意味着这些数字可能用完了?
答案 0 :(得分:2)
资源是32位XID
事务计数器本身,引擎使用它来知道表中行的版本是否与“旧”事务(已提交或已回滚)相关联或尚未提交的事务,如果它在任何给定的事务中可见或不可见。
以超高速率增加XID会产生或增加获得事务ID环绕问题的风险。最糟糕的情况是此问题升级为数据库自关闭以避免数据不一致。
避免事务ID环绕的原因是例行吸尘。这在Preventing Transaction ID Wraparound Failures下的文档中有详细说明。
但autovacuum
是一项后台任务,意在不妨碍前台活动。除此之外,它取消自身而不是锁定其他查询。有时,它可能落后很多。
我们可以想象一个最糟糕的情况,前台数据库活动如此快地增加XID值,以至于autovacuum没有时间冻结具有“旧XID”的行,然后新事务或子事务声明这些XID值,PostgreSQL无法处理的情况。
这可能也是这些前台交易在此过程中保持未提交状态,因此即使是积极的真空也无法做任何事情。
这就是为什么程序员应该对使这个事件更有可能的技术持谨慎态度,比如在大循环中打开/关闭子事务。
范围大约是20亿次交易,但这是在系统设计时无法达到的限制,但由于我们的硬件功能以及我们从数据库中提出的问题不断增加,这将成为问题。