为什么这个存储过程偶尔不能正常工作?

时间:2011-03-02 04:30:56

标签: sql-server stored-procedures azure-sql-database

我有一个名为“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

2 个答案:

答案 0 :(得分:1)

这可能是你的问题吗?

  

在交易中指定时   在SNAPSHOT隔离操作   级别,除非使用行锁   ROWLOCK与其他表结合使用   需要锁定的提示,例如   UPDLOCK和HOLDLOCK。

Source

答案 1 :(得分:1)

不使用ROWLOCK提示,而是在isolation_level设置为SERIALIZABLE的情况下运行更新。

此外,如果在更新中使用OUTPUT子句,则可以在更新完成后立即获取受影响的行列表。这意味着您可以更快地结束您的交易1 DML声明并保持您的酸度。