Почему этот хранимый процесс не работает правильно время от времени? - PullRequest
0 голосов
/ 02 марта 2011

У меня есть таблица с именем «Расписание», которая служит механизмом очереди для нескольких процессов / компьютеров, часто посещающих таблицу. Цель процедуры состоит в том, чтобы выбрать строки не более @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 ]

1 голос
/ 02 марта 2011

Вместо использования подсказки ROWLOCK, запустите обновление с уровнем изоляции_LERIALIZABLE.

Кроме того, если вы используете в своем обновлении предложение OUTPUT, вы можете получить список затронутых строк, как только обновление будет завершено.Это означает, что вы можете быстрее завершить свою транзакцию 1 DML и поддерживать свою ACIDity.

1 голос
/ 02 марта 2011

Может быть, это ваша проблема?

При указании в транзакциях, работающих на уровне изоляции SNAPSHOT, блокировки строк не выполняются, если ROWLOCK не объединен с другими табличными подсказками, требующими блокировок, такими как UPDLOCK.и HOLDLOCK.

Источник

...