Многопоточность и блокировка записей БД

Срочно нужна помощь....

Мне нужно создать приложение .net, которое будет выполнять некоторые массовые операции, скажем, около 2 000 000 записей в таблице. Существует окно возможностей, в котором приложение должно запуститься и попытаться обработать как можно больше строк. Я думаю, что если у меня может быть несколько потоков приложения, которые будут принимать 2000 записей за раз и обрабатывать их, оно сможет обрабатывать больше. Однако это будет довольно дорого на сервере базы данных. Из того, что мне сказали, сервер базы данных — мощная машина, и он должен справляться с нагрузкой.

Кроме того, при приеме только 2000 строк за раз, если приложение остановится в середине своей обработки, оно будет знать, где взять снова.

Итак, я думаю, что я спрашиваю...

1) Как я могу заставить приложение собирать строки и блокировать эти строки, чтобы они не были назначены другому потоку?

2) Какой интеллект можно запрограммировать в приложении, чтобы оно могло продолжить обработку с того места, где оно было остановлено в последний раз?

Спасибо

KP


person Community    schedule 31.07.2009    source источник


Ответы (3)


Вместо того, чтобы изобретать велосипед, вы должны сделать это с помощью служб SQL Server Integration Services (SSIS). Он оптимизирован для этих сценариев, особенно в выпуске 2008 года.

person John Saunders    schedule 31.07.2009
comment
Джон, это то направление, в котором я изначально хотел двигаться. Но администраторы баз данных этой компании боятся SSIS. Они не могут указать вескую причину, почему НЕ хотят использовать SSIS. - person ; 01.08.2009
comment
Ну тогда они дураки. Службы SSIS оптимизированы для этих сценариев гораздо лучше, чем все, что вы или ваши администраторы баз данных, вероятно, создадите. Это, так сказать, одна из его задач. Они могут думать, что это все еще старый DTS, и в этом случае им следует уделять больше внимания прогрессу, когда он происходит. - person John Saunders; 01.08.2009

Я согласен с Джоном в том, что в службах SSIS есть множество встроенных интеллектуальных функций для таких сценариев, и, вероятно, это лучший выбор, на который можно потратить свое время.

Для справки, к таким проблемам вы подходите, разбивая свои данные. Я говорю не о физическом разбиении хранилища (т.е. добавить разбиение таблиц), а о логическом, обрабатывающем разбиении. Вы делите свои 2 млн. записей в N разделах на основе имеющихся у вас критериев, которые можно использовать на уровне доступа к данным, например. индексированный столбец, а затем выделить N процессоров, каждый из которых начнет работать в своем собственном разделе. Идея состоит в том, чтобы процессоры не перекрывались при попытке доступа к одним и тем же строкам. «Процессоры» могут быть потоками или, что еще лучше, ThreadPool ставит в очередь рабочие элементы, которые используют асинхронные методы доступа к базе данных.

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

with cte as (
   select top (@batchSize) *
   from myTable with (rowlock, updlock, readpast)
   where <record is ready to be processed>)
update cte
   set <mark record processing>
output inserted.*

Хитрость заключается в блокирующих подсказках, используемых при выборе: при принудительной блокировке и блокировке записи блокируются для обработки текущим процессором. Добавляя подсказку readpast, каждый процессор будет пропускать записи, которые уже заблокированы другими процессорами. Таким образом, каждый процессор получает свою собственную партию записей @batchSize для обработки, какой бы ни была обработка.

Важно понимать, что все эти комментарии относятся к обработке, которая включает в себя что-то вне базы данных, например вызов веб-службы, печать бумажного бланка или что-то подобное. Если вся обработка выполняется в базе данных, то вы должны просто выразить ее как одно обновление T-SQL и позволить оптимизатору запросов использовать параллельные запросы по своему усмотрению.

person Remus Rusanu    schedule 31.07.2009
comment
Джон, это то направление, в котором я изначально хотел двигаться. Но администраторы баз данных этой компании боятся SSIS. Они не могут указать вескую причину, почему НЕ хотят использовать SSIS. - person ; 01.08.2009

я бы сделал так:

  • настройте одну таблицу (изначально пустую) для хранения ПК ваших основных строк. Назовите это PKs_Done_Table
  • Один поток «выбрать бла из таблицы, в которой нет pk (выбрать pk из PKs_done_Table)
  • тот же поток захватывает строки (или блоки строк — используйте NTILE или множественное чтение) из этого выбора и передает их другим потокам для фактической обработки.

Обработка потоков:

  • принимает строки/блоки строк
  • начать транзакцию
  • делает работу
  • вставляет pks готовой работы в PKs_done_table
  • совершает транзакцию.

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

person LoztInSpace    schedule 09.08.2013