Как я могу избежать тупика SQL во время чтения / обновления в хранимой процедуре - PullRequest
0 голосов
/ 11 июня 2019

У меня есть процедура, используемая для отправки изменений в очереди в другую систему. Процедура была создана несколько лет назад, и мы много думали, чтобы предотвратить тупики во время ее выполнения. На прошлой неделе мы начали видеть тупики, но не можем идентифицировать образец. Когда начинают возникать тупики, они могут продолжаться более суток или всего нескольких часов. До сих пор периоды низкой активности показывали мало блокировок или вообще не имели их, но периоды высокой активности не выявили взаимоблокировок для тысяч тупиков. 12-часовой период с неизменно высокой активностью не имел тупиков. Более медленный 12-часовой период имел более 4000 тупиков.

То, что я нашел в существующих сообщениях, заставляет меня думать, что я должен быть доволен тем, что у меня есть, и не беспокоиться о взаимоблокировках, но отсутствие какого-либо паттерна частоты / появления трудно принять. Без шаблона я не могу дублировать в нашей тестовой среде.

Вот процедура, при которой возникает тупик. У нас было целых 30 сервисов, вызывающих эту процедуру для обработки изменений. Сегодня мы работаем медленно и работаем только пятью службами (на пяти отдельных серверах), но взаимоблокировки продолжаются.

ALTER PROCEDURE [dbo].[retrieveAndLockTransactionChangeLogItems]
@serverName VARCHAR(50)
AS

--Create a common-table-expression to represent the data we're looking
--for.  In this case, all the unprocessed, unlocked items for a 
--transaction.

WITH cte AS 
(
  SELECT t.* 
  FROM TransactionChangeLog t WITH (UPDLOCK, ROWLOCK, READPAST)
  WHERE t.intTransactionID = 
    (SELECT TOP 1 t1.intTransactionID
    FROM TransactionChangeLog t1 WITH (ROWLOCK, READPAST)
    INNER JOIN TransactionServices s ON 
        s.intTransactionID = t1.intTransactionID
    WHERE s.ProductionSystemDefinitionID > 2 --SoftPro v4
    AND t1.bitProcessed = 0 
    AND t1.bitLocked = 0
    AND t1.intSourceID = 1
    AND NOT EXISTS(SELECT t2.intChangeID 
                  FROM TransactionChangeLog t2 WITH (ROWLOCK, READPAST)
                  WHERE t2.intTransactionID = t1.intTransactionID 
                  AND t2.bitLocked = 1)
    AND NOT EXISTS (SELECT ts.intServiceID 
                   FROM TransactionServices ts
                   WHERE ts.intTransactionID = t1.intTransactionID 
                   AND ts.intStatusID in (0, 5, 6, 7))
    ORDER BY t1.Priority, t1.dtmLastUpdatedDate, t1.dtmChangeDate)
  AND t.bitProcessed = 0
)

--Now update those records to Locked.
UPDATE cte 
SET bitLocked = 1, 
    dtmLastUpdatedDate = GETUTCDATE(), 
    dtmLockedDate = GETUTCDATE(), 
    LockedBy = @serverName

--Use the OUTPUT clause to return the affected records. 
--We do this instead of a SELECT then UPDATE because it acts as a
--single operation and we can avoid any deadlocks.
OUTPUT 
Inserted.intChangeID AS 'ChangeID',
Inserted.intSourceID AS 'SourceID',
Inserted.bnyChangeData AS 'ChangeData',
Inserted.intChangeDataTypeID AS 'ChangeDataTypeID',
Inserted.intTransactionID AS 'TransactionID',
Inserted.intUserID AS 'UserID',
Inserted.dtmChangeDate AS 'ChangeDate',
Inserted.bitLocked AS 'Locked',
Inserted.dtmLockedDate AS 'LockedDate',
Inserted.bitProcessed AS 'Processed',
Inserted.dtmLastUpdatedDate AS 'LastUpdatedDate',
Inserted.Retries,
Inserted.LockedBy,
Inserted.ServiceID,
Inserted.Priority

Исходя из истории, до прошлой недели я не ожидаю никаких тупиков от этой процедуры. На этом этапе я был бы просто рад понять, почему / как мы теперь заходим в тупики.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...