没有锁定的全局修订

Global revision without locking

鉴于这套规则,是否可以在 SQL 中实施?

  1. 两个不修改相同行的事务应该能够运行并发。不应发生锁定(或至少应尽可能减少它们的使用)。
  2. 事务只能读取提交的数据。
  3. 版本在系统中被定义为一个整数值。
  4. 新事务必须能够递增和查询新修订。此修订将应用于事务修改的每一行。
  5. 没有 2 个事务可以共享相同的修订版。
  6. 在事务 Y 之前提交的事务 X 的修订版必须低于分配给事务 Y 的修订版。

我想使用整数作为修订版,以优化查询自特定修订版以来所有更改的方式。像这样:

SELECT * FROM [DummyTable] WHERE [DummyTable].[Revision] > clientRevision

我当前的解决方案使用带有单行 [LastRevision] 的 SQL table [GlobalRevision] 来保留最新版本。我所有事务的隔离级别都设置为快照。

此解决方案的问题在于,具有单行 [LastRevision] 的 [GlobalRevision] table 成为争论的焦点。这是因为我必须在事务开始时增加修订,以便我可以将新修订应用于修改后的行。这将在整个事务期间锁定 [LastRevision] 行,从而终止并发。即使两个并发事务修改完全不同的行,它们也不能同时执行(规则 #1:失败)。

SQL中有什么模式可以解决这类问题吗?一种解决方案是使用 Guid 并保留修订历史记录(如 git 修订),但这比仅拥有一个我们可以比较以查看修订是否比另一个修订新的整数要容易得多。

更新:

此业务案例是创建一个在客户端和服务器之间进行数据同步的 Baas 系统(后端即服务)。以下是此类系统的一些用例:

如您所见,全局修订让我可以对服务器上提交的每个更改进行修订,并且根据该修订,我可以根据客户端的特定修订确定需要将哪些更新发送给客户端。

这需要扩展到可以并行推送更新的数千个用户,并且这些更改必须同步到其他连接的用户。因此,执行交易所需的时间越长,其他用户接收更改通知所需的时间就越长。

出于这个原因,我想尽可能避免争用。我不是 SQL 方面的专家,所以我只是想确保没有遗漏任何能让我轻松做到这一点的东西。

您尝试的最简单方法可能是使用 SEQUENCE 作为您的修订号,假设您使用的是 SQL 2012 或更新版本。这是一种生成自动递增值的轻量级方法,您可以根据规则将其用作修订 ID。与使用成熟的 table.

相比,大规模获取它们应该不会受到您描述的争用问题的影响。

您确实需要知道,如果给定的事务回滚,您最终可能会出现修订号差距,因为 SEQUENCE 值在事务范围之外运行。来自文章:

Sequence numbers are generated outside the scope of the current transaction. They are consumed whether the transaction using the sequence number is committed or rolled back.

如果您可以放宽对整数修订号的要求并满足于了解给定时间点的数据,您也许可以使用 Change Data Capture, or, in SQL 2016, Temporal Tables。这两种技术都允许您 "turn back time" 并查看数据在已知时间戳处的样子。