提交事务时自动设置 SERIAL 值

Atomically set SERIAL value when committing transaction

假设我有一个 table,我想在其中使用 serial 作为主键来请求客户端进行更改。客户会问"give me the changes after key X"。如果不使用 SERIALIZABLE 隔离级别或锁定,这很容易出现竞争条件。

事务A可以先启动,然后写,然后花很长时间提交。同时,事务 B 将在 A 提交之前启动并提交。来自 B 的写入将获得比来自 A 的写入更高的主键。如果客户端现在请求更改,它将错过来自 A 的尚未提交的写入,并记下最新的最高主键。所以即使在 A 提交之后,客户端也永远不会看到该更改,因为它的密钥低于客户端已经获得的更改。

是否可以在提交时自动确定 serial(或来自计数器的类似值)的值,以便我们保证在提交时它会高于所有其他值,而低于比所有这一切都将在它之后被承诺?如果不是,解决此问题的最佳方法是什么?

Postgres 9.5 引入了与此问题相关的新功能:提交时间戳.

您只需在 postgresql.conf 中激活 track_commit_timestamp(并重新启动!)即可开始跟踪提交时间戳。然后可以查询:

SELECT * FROM tbl
WHERE  pg_xact_commit_timestamp(xmin) >= '2015-11-26 18:00:00+01';

阅读 Postgres Wiki 中的第 "Commit timestamp tracking" 章。
相关 utility functions in the manual.

函数波动性仅为 VOLATILE,因为交易 ID (xid) 可以根据定义回绕。因此,您无法在其上创建功能索引
您可以在有限的时间范围内为应用程序的函数包装器伪造 IMMUTABLE 波动性,但您需要了解其中的含义。相关案例更多解释:

  • Does PostgreSQL support "accent insensitive" collations?

对于许多只对提交顺序(而不是绝对时间)感兴趣的用例(比如你的?),使用 xmin 转换为 bigint 可能更有效”直接”(xmin::text::bigint)而不是提交时间戳。 (xid 在内部是一个无符号整数,上半部分不适合带符号的 integer。)再次注意由于可能的 xid 环绕而造成的限制。

出于同样的原因,提交时间戳不会无限期保留。对于中小型数据库,xid 环绕几乎不会发生——但如果集群运行时间足够长,它最终会发生。阅读手册中的 "Preventing Transaction ID Wraparound Failures" 章节了解详情。