Самый быстрый способ чтения / записи на сервер SQL с большим набором данных? - PullRequest
3 голосов
/ 26 августа 2010

У меня около 60 миллионов записей в базе данных, и я должен обработать все из них.Таким образом, идея состоит в том, чтобы использовать код C # для чтения данных, их обработки и последующего помещения в базу данных.Данные не приходят и не попадают в одну и ту же таблицу - задействованы несколько таблиц.

Я хочу посмотреть, что лучше для этого сделать?Должен ли я читать 100К записей за раз в наборе данных, а затем обрабатывать каждую запись, а затем использовать массовую вставку в базу данных и затем читать следующий набор?

Ответы [ 2 ]

2 голосов
/ 27 мая 2012

Не подходите близко ни к DataSet, ни к DataAdapter!

Для сброса данных используйте DataReader - используйте текст SQL или вызов Stored Proc через SqlCommand, вызвав для него ExecuteReader. Затем вы можете извлекать записи из DataReader по одной, БЕЗ любого багажа для отслеживания объектов, который поставляется с DateSet, Entity Framework или Linq to SQL, или NHibenate - все эти платформы имеют добавленные слои, чтобы вы могли делать отслеживание объектов и изменений - которое вам не нужно и будет только накладными расходами для вас.

Когда вы записываете свои результаты обратно в базу данных, делайте это с помощью SqlBulkCopy, с включенной функцией TableLock и со свойствами базы данных, для которых для «Модель восстановления» установлено любое значение, кроме «Полный». Убедитесь, что ограничения для целевой таблицы отключены, и что индексы не определены (затем удалите и заново создайте в конце, если вам нужно).

SqlBulkCopy выполняет свою собственную пакетную обработку при отправке обратно на SQL Server, ЕСЛИ вы обязательно указываете BatchSize (по умолчанию все в одной партии). Возможно, вы также захотите установить UseInternalTransaction для SqlBulkCopy, чтобы каждый пакет выполнялся в отдельной транзакции - это еще больше сократит использование журнала транзакций.

Читатель и ветка писателя могут помочь, а могут и нет, я не профилировал разницу. Вам также может понадобиться один или несколько потоков обработки или другой механизм, если упомянутый вами «сторонний процесс» отнимает много времени.

Можно сделать все это в одном потоке, по одной записи за раз, и это может быть довольно быстро (в зависимости от стоимости обработки, которую вы выполняете).

Если вам НУЖНО использовать несколько потоков, НЕ ОБМЕНЯЙТЕ отдельные записи между ними, поскольку вы потеряете слишком много циклов ЦП, переключая потоки: разбейте его на «разумные» партии. «Разумный» может составлять от 1 до 100 тыс. Записей в зависимости от размера записи и выполняемой вами обработки. Может быть, даже если дать Parallels возможность сделать это для вас.

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

2 голосов
/ 26 августа 2010

Как правило, самый быстрый способ - это делать все на сервере в пакетах SQL.

Если вы настаиваете на использовании клиента, то отдельные потоки для чтения и записи могут быть быстрее, чем один для выполнения обоих.Сколько потоков для чтения и записи будет зависеть от оборудования и от того, что вы делаете

РЕДАКТИРОВАТЬ: Разъяснение подхода.

Извлечение и отправка данных на сервер sql связаны как с сетевым вводом-выводом, так и вне процесса.Это означает, что как при чтении, так и при отправке данных ваше приложение тратит время на ожидание передачи данных с диска по сети и в память.Предположим, что получение данных займет 1 час.10 минут для обработки и 1 час для отправки данных обратно в БД.Таким образом, весь ваш процесс займет 2 часа и 10 минут.

Если вы разделите его на три потока: 1 считыватель, 1 процессор, 1 средство обновления.Вы можете получить его до 1 часа.Если вы хорошо пишете свое приложение, вы можете добавить дополнительные потоки для чтения, обработки и записи, но вы можете быть разочарованы результатами из-за таких вещей, как совместное использование строк кэша, как сетевая карта реагирует на множество одновременных запросов и т. Д.

Также, когда вы используете DataAdapter для заполнения набора данных, вы не можете касаться каких-либо данных, пока заполнение не будет завершено.С другой стороны, если вы DataReader, вы можете начать использовать данные, когда закончится первая строка.Это означает, что вам не нужно беспокоиться об ограничении до 100K одновременно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...