2017-01-06 3 views
0

У меня есть приложение, которое соединяется с базой данных SQL Server и циклически проходит через партии записей для выполнения различных задач, а затем соответствующим образом обновляет базу данных (т. Е. «Успех», «ошибка» и т. Д.).Блокировка SQL Server

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

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

В любом случае, было бы идеально, если бы было возможно иметь приложение SELECT 100 записей за раз и «блокировать их» в базе данных, пока приложение обрабатывает их И так, чтобы другие пользователи могли запускать приложение и SELECT другой набор из 100, чтобы не перекрываться. Это возможно? Я попытался провести некоторое исследование по этому вопросу, но, честно говоря, мой опыт работы в SQL Server очень ограничен. Спасибо за любую помощь!

+0

Если столбец LOCKED достаточно для решения проблемы, и единственная проблема - это потенциальные сбои, просто добавьте задание разблокировки мастера, которое будет запущено посреди ночи. – SunKnight0

+0

http://blog.sqlauthority.com/2012/11/15/sql-server-concurrency-basics-guest-post-by-vinod-kumar/ –

+0

http://stackoverflow.com/questions/1138026/sql- server-performance-with-many-concurrent-long-running-queries –

ответ

2

Кажется, что вы пытаетесь создать очередь. Wihin SQL Server, существуют два основных решения для таких сценариев:

[1] Service Broker (см: активация, RECEIVE TOP(1)/TOP(100))

или

[2] Для того, чтобы разработать пользовательскую очередь с использованием таблицы плюс UPDATE/DELETE/SELECT TOP(100) ... FROM dbo.QueueTable WITH(READPAST, ROWLOCK) , Роль этих таблиц намеков выглядит следующим образом:

  • READPAST (ref - see READPAST section) избежать чтения уже заблокированные записи (заблокированы другими параллельными транзакциями)

  • ROWLOCK (ref - see ROWLOCK section) заставляет замки на строке = уровень записи (в отличие от блокировок страниц/разделов/таблиц). Более того, все совпадающие потоки, которые пытаются читать и (затем) обрабатывать записи из таблицы очередей, должны использовать один и тот же шаблон доступа к данным (READPAST, ROWLOCK).

Вы можете найти более подробную информацию в блоге Ремуса здесь: http://rusanu.com/2010/03/26/using-tables-as-queues/

Один шаблон для считывания и обработки записей из таблицы - очереди может быть:

SET XACT_ABORT ON 
BEGIN TRY 
-- BEGIN TRAN 

CREATE TABLE #SelectedRecords TABLE (
... 
) 
DELETE TOP(100) FROM dbo.QueueTable WITH(READPAST, ROWLOCK) 
OUTPUT deleted.Col1, deleted.Col2, ... INTO #SelectedRecords (Col1, Cold2, ...); 

... Do something with those 100 records ... 

-- COMMIT 
END TRY 
BEGIN CATCH 
-- IF @@TRANCOUNT > 0 
-- BEGIN 
--  ROLLBACK 
-- END 
END CATCH 

Если комментируемые линии ООН Затем SQL Server будет использовать один TX для чтения данных из таблицы очередей, а также во время обработки данных. Если одно исключение перехвачено блоком catch, тогда SQL Server откажется от текущего TX (включая эти 100 записей, считанных и удаленных из таблицы очередей).

Примечание: в идеале блок обработки данных не должен открывать/создавать другой/вложенный TX.

Примечание # 2: вы должны проверить, если индексы (или структура кучи), определенная на поддержку таблицы очереди (или нет) блокировки строк таким образом:

SELECT i.allow_row_locks, * 
FROM sys.indexes i 
WHERE i.object_id = OBJECT_ID('dbo.QueueTable') 

Примечание # 3: Если allow_row_locks бит ложно/0, то вы можете изменить его, используя

+0

Спасибо за подробный ответ, хотя я все еще не совсем уверен, что это то, что я ищу. Было бы чем-то вроде этого работать, если обработка данных НЕ обрабатывалась через SQL Server, а вместо этого серверный код, например PHP, для выполнения конкретных задач? Идея заключалась бы в том, чтобы захватить 100 записей за один раз через SQL, пропустить записи через PHP и выполнить различные задачи, а затем на основе результатов этих задач обновить БД с помощью «Завершено» или «Ошибка» и т. Д. ... –

+1

Да. Возможно. Для Service Broker существуют так называемые «внешние активаторы» (поиск по ключевым словам: внешний агент-посредник сервис-брокера sql-сервера). Для таблицы очередей я бы добавил состояние столбца со следующими допустимыми значениями: 0 новых, 1 обработка, 2 обработанных без ошибок, -1 обработанных с ошибками. Чтобы получить еще 100 предметов из очереди, я бы использовал –

+1

Update qt top (100) set Status = 1 Выход вставлен. * Из dbo.QueueTable как qt с (readpast, rowlock) Где Status = 0 –

Смежные вопросы