2015-04-09 7 views
0

У меня есть система, в которой центральная база данных MSSQL хранит в таблице очередь заданий, которые необходимо выполнить.Опрос базы данных, предотвращение дублирования выборки

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

Единственная выборка выполняется путем приложения клиентской программы хранимой процедуры, которая выполняет запрос (-и) и возвращает идентификатор задания. Затем клиентское приложение извлекает информацию о задании путем запроса по идентификатору и задает задание в соответствии с обработкой.

Производительность в порядке; единственная проблема, которую мы почувствовали, заключается в том, что, поскольку клиентское приложение должно запрашивать детали и выполнять проверку до того, как задание помечено как обработанное, в очень редких случаях (каждые несколько тысяч рабочих мест), два клиента берут ту же работу ,

Как способ решения этой проблемы, я предлагал иметь начальную хранимую процедуру, которая запускает «тег», которую он извлекает с указанием времени и даты. Хранимая процедура при запросе записей записывает только те записи, где этот «тег» - определенное количество времени, например, 5 секунд. Таким образом, если хранимая процедура выполняется дважды в течение 5 секунд, второй экземпляр не будет получать ту же работу.

Может ли кто-нибудь предвидеть какие-либо проблемы с устранением проблемы или предложить альтернативное решение?

ответ

0

Используйте поле UNIQUEIDENTIFIER в качестве вашего маркера. Когда хранимая процедура запускается, заблокируйте строку, которую вы читаете, и обновите поле с помощью NEWID(). Вы можете пометить свое заявление о опросе, используя что-то вроде WITH(READPAST), если вы беспокоитесь о проблемах с блокировкой.

Причина использования GUID здесь заключается в том, чтобы иметь уникальный идентификатор, который будет служить для маркировки партии. Ваш звонок NEWID() гарантирует вам уникальное значение, которое будет использоваться для предотвращения случайного сбора одинаковых данных дважды. GETDATE() не будет работать здесь, потому что вы можете в конечном итоге иметь два вызова, которые разрешаются в одно и то же время; BIT не будет работать, потому что он не будет однозначно отмечать партии для сбора или отчетности.

Например,

declare @ReadID uniqueidentifier 
declare @BatchSize int = 20; -- make a parameter to your procedure 

set @ReadID = NEWID(); 

UPDATE tbl WITH (ROWLOCK) 
SET HasBeenRead = @ReadID -- your UNIQUEIDENTIFIER field 
FROM (
    SELECT TOP (@BatchSize) Id 
    FROM tbl WITH(UPDLOCK ROWLOCK READPAST) 
    WHERE HasBeenRead IS null ORDER BY [Id]) 
AS t1 
WHERE (tbl.Id = t1.Id) 

SELECT Id, OtherCol, OtherCol2 
FROM tbl WITH(UPDLOCK ROWLOCK READPAST) 
WHERE HasBeenRead = @ReadID 

И тогда вы можете использовать оператор опроса, как

SELECT COUNT(*) FROM tbl WITH(READPAST) WHERE HasBeenRead IS NULL 

адаптированного здесь: https://msdn.microsoft.com/en-us/library/cc507804%28v=bts.10%29.aspx

+0

Спасибо. Я прочитал эту прикрепленную ссылку и не вижу никакой причины, почему это лучше, чем просто использование логического поля? – Raiden616

+0

Если вы используете 'BIT', вы не знаете, какие элементы являются частью партии или нет. Предложение 'WHERE HasBeenRead = 1' в конечном итоге будет захватывать все предыдущие партии. Это также мешает вам выполнять правильное отслеживание отчетов/ошибок на определенных партиях, так как все они выглядят одинаково. –

+0

Я обновил ответ, чтобы добавить немного больше объяснений по этому поводу. –