Я согласен с Джоном в том, что в 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.*
Хитрость заключается в подсказках по блокировке, используемых в select: путем принудительной и повторной блокировки записи блокируются для обработки текущим процессором. При добавлении подсказки readpast каждый процессор будет пропускать записи, которые уже заблокированы другими процессорами. Таким образом, каждый процессор получает свою собственную серию записей @batchSize для обработки независимо от того, какая обработка выполняется.
Важно понимать, что все эти комментарии относятся к обработке, которая включает в себя что-то вне базы данных, например, выполнение вызова веб-службы, печать бумажного бланка или что-то подобное. Если вся обработка выполняется в базе данных, вы должны просто выразить ее как отдельное обновление T-SQL и позволить оптимизатору запросов использовать параллельные запросы по своему усмотрению.