寻求有关 SQL Server 死锁问题的帮助

Posted

技术标签:

【中文标题】寻求有关 SQL Server 死锁问题的帮助【英文标题】:Looking for assistance with SQL Server Deadlock issue 【发布时间】:2012-12-28 20:48:57 【问题描述】:

寻求帮助解决这个死锁问题...我有一个存储过程,它被许多进程相当频繁地调用,但在一个小表上(行数低至数千)...偶尔,我在 proc 上遇到了死锁。 Proc 的目的是返回下一个“符合处理条件”的行。不将同一行返回给 proc 的两个同时调用是非常重要的......(这部分工作正常)......但我不明白为什么有时会出现死锁。

这是一个 SQL Azure 数据库

感谢帮助

CREATE PROCEDURE [dbo].[getScheduledAccounts_Monitor]
    -- Add the parameters for the stored procedure here
    @count int,
    @timeout int = 1200,
    @forcedAccountId uniqueidentifier = NULL
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

    DECLARE @batchId uniqueidentifier
    SELECT @batchId = NEWID()

    BEGIN TRAN

    -- Update rows
    UPDATE Schedule 
    WITH (ROWLOCK)
    SET 
        LastBatchId = @batchId, 
        LastStartedProcessingId = NEWID(), 
        LastStartedProcessingTime = GETUTCDATE(),
        LastCompletedProcessingId = ISNULL(LastCompletedProcessingId, NEWID()),
        LastCompletedProcessingTime = ISNULL(LastCompletedProcessingTime, GETUTCDATE())
    WHERE 
        ActivityType = 'Monitor' AND 
        IsActive = 1 AND
        AccountId IN (
            SELECT TOP (@count) AccountId 
            FROM Schedule 
            WHERE 
                (LastStartedProcessingId = LastCompletedProcessingId OR LastCompletedProcessingId IS NULL OR DATEDIFF(SECOND, LastStartedProcessingTime, GETUTCDATE()) > @timeout) AND 
                IsActive = 1 AND ActivityType = 'Monitor' AND
                (LastStartedProcessingTime IS NULL OR DATEDIFF(SECOND, LastStartedProcessingTime, GETUTCDATE()) > Frequency)
            ORDER BY (DATEDIFF(SECOND, LastStartedProcessingTime, GETUTCDATE()) - Frequency) DESC
        ) AND
        AccountId = ISNULL(@forcedAccountId, AccountID)

    -- Return the changed rows
    SELECT AccountId, LastStartedProcessingId, Frequency, LastProcessTime, LastConfigChangeTime, ActivityType
    FROM Schedule 
    WHERE LastBatchId = @batchId

    COMMIT TRAN
END

【问题讨论】:

您是否有权获取死锁图,它会告诉您为什么会发生死锁? (抱歉,从来没有搞砸过 Azure,所以不知道是否可以访问。) 如果没有死锁图,我会尝试将WITH(UPDLOCK) 提示添加到最后一个选择语句。 不要以为我可以得到死锁图。 WITH(UPDLOCK) 语句不起作用,实际上它使事情变得更糟 - 它用 batchId 标记了某些行,但没有返回它们 【参考方案1】:

您可以使用应用程序锁来确保单次执行。下面的文章适用于 SQL 2005,但我相信该解决方案也适用于较新的版本。

http://www.sqlteam.com/article/application-locks-or-mutexes-in-sql-server-2005

【讨论】:

看起来很酷,并且似乎在 SQL Azure 中受支持,但是,我需要跨应用程序实例进行锁定。我有许多服务器,每个服务器都执行许多线程,所有这些都在“寻找工作”......如果我要重新设计这个过程,我可能会选择 Azure Queue,但这不是现在的选择 它被称为“应用程序”锁,但它是一个数据库级别的功能,所以我很确定它可以跨应用程序实例工作,只要它们在数据库的单个实例上工作。

以上是关于寻求有关 SQL Server 死锁问题的帮助的主要内容,如果未能解决你的问题,请参考以下文章

UPDATE 上的 SQL Server 死锁

了解sql server的死锁图

寻求有关如何从特定数组中获取所有过滤列表的帮助

在 SQL Server 中检索一周前的死锁

SQL Server扩展事件-- 使用system_health默认跟踪会话监控死锁

SQL Server Profiler的简单使用