轮询表中的新记录

Mic*_*lGG 2 sequence identity change-tracking

我们有一个附加+只读的表。我们希望多个应用程序以一种廉价且简单的方式(无需更改跟踪)使用该数据库中显示的所有新行。

让每个应用程序记录最后一个 ID 的简单建议似乎并不安全。假设 3 个连接(2 个作者和 1 个读者)这样做:

W1: BEGIN TRAN, INSERT 1000 Records (IDs 1-1000)
W2: BEGIN TRAN, INSERT 1000 Records (IDs 1001-2000)
W2: COMMIT
R1: SELECT * WHERE Id > 0 (last sync value)
W1: COMMIT (or possibly ROLLBACK)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,阅读器将获得记录 1001-2000,并将 2000 保存为最高 ID。显然这是不正确的。假设各种编写器以不同的速度运行(因此我们永远不能假设它们会因延迟或性能而按顺序提交),有哪些选择?

我们是否必须求助于更改跟踪之类的方法,或者要求每个应用程序保存最后的 (batch*writers*x) ID 并重新读取它们以确保它们没有遗漏任何一个?

回滚和序列中的其他间隙(MSSQL 可以将 ID 跳转 1000;很确定其他 DB 在某些情况下会这样做)使得尝试猜测是否跳过行变得很复杂。另外,批量插入可能不是正确的批次;它们可以由多个 INSERT 语句组成,这意味着每个 tx 甚至可能没有分配一个连续的 ID 块。

如果有特定于该系统的 hack,我们目前正在使用 MSSQL 2012,但我对一般情况更感兴趣。

Pau*_*ite 5

一些实现细节取决于您需要从该表中获得什么类型的行为(例如 FIFO),但队列表的典型设计使用DELETE了一个OUTPUT子句:

DELETE TOP (n)
FROM QueueTable WITH (ROWLOCK, READPAST)
OUTPUT deleted.RecordID;
Run Code Online (Sandbox Code Playgroud)

或者,如果需要有序移除:

DELETE FROM
(
    SELECT TOP (n) RecordID
    FROM QueueTable WITH (ROWLOCK, READPAST)
    ORDER BY RecordID
) AS DF
OUTPUT deleted.RecordID;
Run Code Online (Sandbox Code Playgroud)

如果处理后记录应保留在表中,则该表将有一个额外的列来记录状态(例如新建、处理、已处理)以及可能拥有该行的进程 ID(如果正在处理或已处理)。然后修改出队代码以仅选择具有所需状态的记录。另一种设计是将DELETE行同时移动到单独的审计/存档表。正如我所提到的,具体的解决方案取决于具体的要求。