使用Postgres中的rowversions实现增量客户端更新

时间:2015-02-11 00:39:16

标签: sql sql-server database postgresql

我是Postgres的新人并且喜欢它到目前为止。我已经很多想到了这个问题,RTFM尽我所能,但是走到了尽头,所以我需要朝着正确的方向努力。

我正在设计一个数据库,其中每个感兴趣的实体都有一个rowversion列,从全局序列中分配一个值。因此,在最简单的情况下,在包含两行的emps表中:emp1 rowversion@3emp2 rowversion@5,我知道emp2emp1之后进行了修改(即在以后的交易中 - 如果同一交易中的行具有相同的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值与结果数据一起传递回客户端。
  4. 由于rowversion @ 6和@ 8的行仍在进行中,new_anchor必须为@ 5,,以便我们的范围查询不会错过任何未提交的更新。现在,客户可以确信它拥有一切,直到@ 5。

    因此,实际问题已被提炼出来:如何在不强制new_anchor或严重损害绩效的情况下安全确定SERIALIZABLE如何安全?

    你可以告诉我,我已经从SQL Server借用了这个想法,这个问题可以通过min_active_rowversion()函数轻松解决。在上面的场景中,此函数将返回@ 6,因此new_anchor可以安全地min_active_rowversion() - 1。我有点想知道如何使用active_rowversions表,触发器和SELECT min(id) FROM active_rowversions在Postgres中实现这一点,但这需要READ UNCOMMITTED隔离,这在Postgres中是不可用的。< / p>

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

1 个答案:

答案 0 :(得分:5)

事实证明,解决方案比最初想象的要简单得多,感谢Postgres'System Information Functions

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

最好的部分是64位,永久性,不受吸尘:

  

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

Postgres确实令人惊叹。