我有一个名为“Schedule”的表,它充当多个进程/计算机频繁访问表的队列机制。 proc的目标是获取不超过@count行的行,这些行有资格被拾取(他们的LastCompletedProcessingId& LastStartedProcessingId必须匹配)并将它们标记为已被拾取(将LastStartedProcessingId更改为NEWID()),这样下一个进程就不会尝试获取已标记的行。
我的问题是,在极少数情况下,当多个客户端在非常接近的时间调用proc时,多个客户端最终会使用相同的行。这怎么可能?我该如何避免呢?桌子本身并不大。 @timeout不是问题,因为这些东西不需要超过300秒来处理,并且我有一个日志,在进程获取多个记录之前,它们没有运行超过300秒。这是在SQL Azure中运行
有关如何做到这一点的任何想法? 感谢
CREATE PROCEDURE X
@count int,
@timeout int = 300
AS
BEGIN
SET NOCOUNT ON;
DECLARE @batchId uniqueidentifier
SELECT @batchId = NEWID()
BEGIN TRAN
-- Update rows
UPDATE Schedule
WITH (ROWLOCK)
SET
LastBatchId = @batchId,
LastStartedProcessingId = NEWID(),
LastStartedProcessingTime = GETDATE()
WHERE
AccountId IN (
SELECT TOP (@count) AccountId
FROM Schedule
WHERE
(LastStartedProcessingId = LastCompletedProcessingId OR LastCompletedProcessingId IS NULL OR DATEDIFF(SECOND, LastStartedProcessingTime, GETDATE()) > @timeout) AND
(LastStartedProcessingTime IS NULL OR DATEDIFF(SECOND, LastStartedProcessingTime, GETDATE()) > Frequency)
ORDER BY (DATEDIFF(SECOND, LastStartedProcessingTime, GETDATE()) - Frequency) DESC
)
-- Return the changed rows
SELECT AccountId, LastStartedProcessingId, Frequency, LastProcessTime, LastConfigChangeTime
FROM Schedule
WHERE LastBatchId = @batchId
COMMIT TRAN
END
答案 0 :(得分:1)
答案 1 :(得分:1)
不使用ROWLOCK提示,而是在isolation_level设置为SERIALIZABLE的情况下运行更新。
此外,如果在更新中使用OUTPUT子句,则可以在更新完成后立即获取受影响的行列表。这意味着您可以更快地结束您的交易1 DML声明并保持您的酸度。