小编典典

在Postgres中使用行版本实现增量客户端更新

sql

我是Postgres的新手,到目前为止很喜欢它。我已经尽了最大的努力来考虑这个问题,RTFM已尽我所能,但是已经走到了尽头,因此我需要朝着正确的方向轻推。

我正在设计一个数据库,其中每个感兴趣的实体都有一个rowversion从全局序列中分配值的列。因此,在最简单的情况下,在emps具有两行的表中:emp1withrowversion@3emp2with
rowversion@5,我知道之后emp2进行了修改emp1(即在以后的事务中-
不必介意同一事务中的行是否具有相同的rowversion)。

这构成了 数据同步逻辑 的基础,在该 同步中 ,知道自己拥有@ 3之前的所有信息的客户端可以使用诸如之类的查询来获取最新更新SELECT * FROM emps WHERE rowversion>3 and rowversion<=new_anchor

这是一个已经更新@ 3的客户端的示例方案-由于以下原因,请进行以下事务:

@3 - committed
@4 - committed
@5 - committed
@6 - in progress - not committed yet
@7 - committed
@8 - in progress - not committed yet
@9 - committed

客户端更新分三个阶段执行:

  1. 询问数据库是否合适new_anchor
  2. 执行SELECT * FROM emps WHERE rowversion>3 and rowversion<=new_anchor
  3. new_anchor值与结果数据一起传递回客户端。

由于带有rowversion@ 6和@ 8的行仍在进行中,new_anchor因此必须为@ 5,
以便我们的范围查询不会丢失任何未提交的update 。现在,客户可以放心,直到@ 5为止,一切都可以满足。

因此,实际问题 得以 提炼: 如何new_anchor在不强迫SERIALIZABLE或严重损害性能的情况下安全地确定这一点?

如您所知,我是从SQL
Server借用这个想法的,该问题通过该min_active_rowversion()函数可以轻松解决。在上述情况下,此函数将返回@
6,因此您new_anchor可以放心地成为min_active_rowversion() - 1。我有点了解如何使用active_rowversions表,触发器和在Postgres中实现此功能SELECT min(id) FROM active_rowversions,但这需要READ UNCOMMITTED隔离,而Postgres中不提供隔离功能。

我真的很感谢任何帮助或想法。


阅读 217

收藏
2021-04-17

共1个答案

小编典典

事实证明,得益于Postgres的系统信息功能,该解决方案比最初想像的要简单得多。

  • txid_current()可以在触发器中用于分配记录的rowversion
  • txid_snapshot_min(txid_current_snapshot())可以用来获得最小活动事务,其方式与SQL Server用户可能使用的方式相同min_active_rowversion()

最好的部分是这些是64位的,永久的,不受清除的影响:

这些函数导出64位格式,该格式使用“ epoch”计数器扩展,因此在安装期间不会回绕。

Postgres确实很棒。

2021-04-17