Question

Looking for help solving this deadlock issue... I have a stored proc that is called rather frequently from a number of processes but on a small table (quantity of rows is in low thousands)... Once in a while, I'm getting a deadlock on the proc.
Proc's purpose is to return the next 'eligible for processing' rows. It is very important to not return the same row to two simultaneous calls of the proc.... (that part works fine)... but I can't understand why sometimes there would be a deadlock.

This is a SQL Azure database

Appreciate the help

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
Was it helpful?

Solution

You can use an application lock to ensure single execution. The article below is for SQL 2005 but I am sure the solution applies for newer versions also.

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top