Состояние гонки очереди процесса SQL Server - PullRequest
42 голосов
/ 02 июня 2009

У меня есть очередь заказов, доступ к которой осуществляется несколькими обработчиками заказов с помощью хранимой процедуры. Каждый процессор передает уникальный идентификатор, который используется для блокировки следующих 20 заказов для собственного использования. Хранимая процедура затем возвращает эти записи обработчику заказа, с которым нужно выполнить действия.

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

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

Так явно - Любая идея, почему я испытываю это состояние гонки и как я могу решить эту проблему.

BEGIN TRAN
    UPDATE  OrderTable WITH ( ROWLOCK )
    SET     ProcessorID = @PROCID
    WHERE   OrderID IN ( SELECT TOP ( 20 )
                                        OrderID
                                FROM    OrderTable WITH ( ROWLOCK )
                                WHERE   ProcessorID = 0)
COMMIT TRAN


SELECT  OrderID, ProcessorID, etc...
FROM    OrderTable
WHERE   ProcessorID = @PROCID

Ответы [ 2 ]

55 голосов
/ 02 июня 2009

Редактировать:

Я гуглил, чтобы проверить мой ответ: "Обработка очередей данных в SQL Server с READPAST и UPDLOCK" . Прошло много лет с тех пор, как я читал и играл с этим решением.

Оригинал:

Если вы используете подсказку READPAST, заблокированные строки будут пропущены. Вы использовали ROWLOCK, поэтому вам следует избегать повышения блокировки. Вам также нужно UPDLOCK, как я узнал.

Таким образом, процесс 1 блокирует 20 строк, процесс 2 - следующие 20, процесс 3 - строки с 41 по 60 и т. Д.

Обновление также можно записать так:

UPDATE TOP (20)
    foo
SET
    ProcessorID = @PROCID
FROM
    OrderTable foo WITH (ROWLOCK, READPAST, UPDLOCK)
WHERE
    ProcessorID = 0

Обновление, октябрь 2011

Это можно сделать более элегантно с помощью предложения OUTPUT, если вам нужно SELECT и ОБНОВЛЕНИЕ за один раз.

6 голосов
/ 02 июня 2009

Вы можете использовать Service Broker. Также вы можете использовать sp_getapplock для сериализации доступа к вашим строкам - это устранит условия гонки:

«Содействие параллелизму путем создания собственных замков (мьютексы в SQL)» http://sqlblogcasts.com/blogs/tonyrogerson/archive/2006/06/30/855.aspx

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