如何一致地跟踪SQL数据库表中的所有新行 我想做什么

如何一致地跟踪SQL数据库表中的所有新行 我想做什么,sql,postgresql,Sql,Postgresql,我正在开发一个web服务,它运行在多个服务器实例中,所有实例都访问相同的RDBMS(PostgreSQL)。虽然持久化需要数据库,但它包含的数据很少,这就是为什么每个服务器实例都有一个包含所有数据的缓存。此外,该应用程序非常简单,因为它只在相当简单的表中插入新行,并以预定方式从所有服务器实例中选择该数据(无更新或更改…仅插入和读取) 它目前的实施方式 基本上我有一张大致如下的表: id BIGSERIAL, creation_timestamp TIMESTAMP DEFAULT CURRENT

我正在开发一个web服务,它运行在多个服务器实例中,所有实例都访问相同的RDBMS(PostgreSQL)。虽然持久化需要数据库,但它包含的数据很少,这就是为什么每个服务器实例都有一个包含所有数据的缓存。此外,该应用程序非常简单,因为它只在相当简单的表中插入新行,并以预定方式从所有服务器实例中选择该数据(无更新或更改…仅插入和读取)

它目前的实施方式 基本上我有一张大致如下的表:

id BIGSERIAL,
creation_timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-- further data columns...
服务器每隔几秒钟就会执行类似操作(伪代码):

我遇到的问题 应用程序在更新缓存时跳过某些行。我对问题进行了分析,发现问题的原因如下:

  • 一个服务器实例正在事务上下文中创建新行。从关联序列(id=n)检索新行的id,并设置创建时间戳(值为ts_1)
  • 另一台服务器在不同事务的上下文中执行相同的操作。该事务中的新行获取id=n+1和创建时间戳ts_2(其中ts_1
  • 事务2在事务1之前完成
  • 其中一个服务器执行“选择所有具有创建时间戳>lastMaxTimestamp的行”。它得到n+1行,但不是n1行。它将lastMaxTimestamp设置为ts_2
  • 事务1完成
  • 一段时间后,步骤4中的服务器再次执行“选择具有创建\u timestamp>lastMaxTimestamp的所有行”。但是因为lastMaxTimestamp=ts_2和ts_2>ts_1,所以在该服务器上永远不会读取第n行
  • 注意:当前_时间戳在事务期间具有相同的值,即事务开始时间

    因此,应用程序将不一致的数据放入其缓存,并且无法根据插入时间戳或序列id获取新行。事务隔离级别实际上不会改变任何情况,因为问题本质上是由事务2在事务1之前完成而造成的

    我的问题 我错过什么了吗?我认为必须有一个简单的方法来获取所有新的RDBMS行,但我不能想出一个简单的解决方案。。。至少有一个简单的解决方案是一致的。由于性能原因,无法接受广泛锁定(例如表)。简单地尝试确保从该序列获取所有ID看起来像a)一个复杂的解决方案,b)不容易完成,因为事务期间可能发生回滚(这将导致序列ID未被使用)


    有人有这个解决方案吗?

    经过大量搜索,我找到了适合谷歌搜索的关键字。。。“transaction commit timestamp”将导致各种事务时间戳跟踪和系统列,如xmin:

    这篇文章有一些更详细的信息:

    简言之:

    • 您可以启用postgresql选项来跟踪提交的时间戳,并比较这些时间戳,而不是事务中的当前时间戳/时钟时间戳
    • 不过,似乎只有在事务完成时才对其进行跟踪,而不是在提交时,这使得解决方案不是防弹的。还需要考虑事务ID(Xmin)翻转的进一步问题,例如
    • 逻辑解码/复制是寻找合适解决方案的一个方面

    感谢所有试图帮助我找到答案的人。我希望这个摘要对将来的人有用。

    使用一个始终作为标识生成的
    序列
    /
    列来代替。@GordonLinoff:如问题中所述,应用程序已经使用BIGSERIAL作为id,这并不能提供可能的解决方案。当选择“id>maxId”时,同样的问题也会发生,因为id=n+1的行可以在id=n的行之前创建。如果您不喜欢
    current\u timestamp
    表示事务开始的事实,那么为什么不使用
    clock\u timestamp()
    @a\u horse\u with\u no\u name:这会防止错误场景的发生?当然,时间戳可能不会在事务开始时被锁定,但这并不会真正改变任何事情,或者是吗?您仍然可以让事务2在事务1之后设置时间戳,但在事务1之前提交。
    get all rows with creation_timestamp > lastMaxTimestamp
    lastMaxTimestamp = max timestamp for all data just retrieved
    insert new rows into application cache