2009-05-27 4 views
6

У меня есть запрос Sql, который возвращает мне более полумиллиона строк для обработки ... Процесс не занимает очень много времени, но я хотел бы немного ускорить его с некоторой многопроцессорной обработкой. Учитывая приведенный ниже код, возможно ли многопоточное что-то подобное?Есть ли способ многопоточности SqlDataReader?

using (SqlDataReader reader = command.ExecuteReader()) 
{ 
    while (reader.Read()) 
    { 
     // ...process row 
    } 
} 

Было бы идеально, если бы я мог просто получить курсор в начале и в середине списка результатов. Таким образом, я мог бы обработать записи двумя потоками. Однако SqlDataReader не позволяет мне это делать ...

Любая идея, как я мог бы это достичь?

+0

Если вы знаете, как разделить запрос, вы можете запускать 2 запроса параллельно. – VVS

ответ

6

Настройте очередь производителя/потребителя, при этом один процесс продюсера вытащит из чтения и записи в очередь как можно быстрее, но не выполняет «обработку». Затем некоторое количество процессов (сколько вам нужно зависит от вашей системы), чтобы удалить и обработать каждую запись в очереди.

+0

Хм .. странно, но я не смог найти общий шаблон производителя/потребителя, уже реализованный. Играя с моим собственным сейчас, но ввод здесь оценивается: http://stackoverflow.com/questions/916863/generic-net-produce-consumer –

0

Является ли простой запрос в диапазоне, например, ГДЕ ИД между 1 и 500000? Если это так, вы можете просто начать N запросов, каждый из которых возвращает 1/N диапазона. Но это помогает узнать, где вы узкоколейны с однопоточным подходом. Если вы выполняете непрерывные чтения с одного диска, чтобы выполнить запрос, вы должны, вероятно, придерживаться одного потока. Если он разделен по шпинделям на некоторый диапазон, вы можете разумно настроить свои запросы, чтобы максимизировать пропускную способность с диска (т. Е. Читать с каждого диска параллельно с отдельными запросами). Если вы ожидаете, что все строки будут в памяти, тогда вы можете распараллелить по желанию. Но если запрос более сложный, вы не сможете легко его разбить, не нажимая на себе накладные расходы. В большинстве случаев вышеуказанные варианты не будут применяться хорошо, и производитель/потребитель, о которых упоминал Джоэл, будет единственным местом для распараллеливания. В зависимости от того, сколько времени вы тратите на обработку каждой строки, это может обеспечить только тривиальные выигрыши.

3

Вы не должны читать много строк на клиенте.

При этом вы можете разделить свой запрос на несколько запросов и выполнить их параллельно. Это означает запуск нескольких SqlCommands в отдельных потоках и их отключение каждого раздела результата. A + Вопрос заключается в том, чтобы разбить результат, и это во многом зависит о ваших данных и ваш запрос:

  1. Вы можете использовать диапазон ключей
  2. Вы можете использовать атрибут (например ID betweem 1 and 10000, ID between 10001 and 20000 и т.д.). (например, RecordTypeID IN (1,2), RecordTypeID IN (3,4) и т.д.)
  3. Вы можете использовать синтетический диапазон (то есть. ROW_NUMBER() BETWEEN 1 and 1000 Etc), но это очень проблематично вытащить из правого
  4. Вы можете использовать хэш (например. BINARY_CHECKSUM(*)%10 == 0, BINARY_CHECKSUM(*)%10==1 и т.д.)

Вы просто должны быть очень осторожны, чтобы запросы на разделы не перекрывались и блок во время выполнения (т.е. сканировать те же записи и приобретать блокировки X), таким образом, сериализуя друг друга.

+0

Я не думаю, что это очень хорошая идея. Разработчику не нужно Знайте это о данных (или о том, как это может выглядеть в будущем). Кроме того, любое решение должно быть повторно использовано в других сценариях.Было бы лучше использовать подлинное многопоточное решение, например, упомянутый выше производитель/потребитель. –

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