Загрузить массив CSV-файл в базу данных SQL Server - PullRequest
7 голосов
/ 12 мая 2009

Мне нужно загрузить массивный (16 ГБ, более 65 миллионов записей) CSV-файл в одну таблицу в базе данных SQL Server 2005. У кого-нибудь есть указания на лучший способ сделать это?

Детали

В настоящее время я использую консольное приложение C # (.NET Framework 2.0), чтобы разбить файл импорта на файлы по 50000 записей, а затем обработать каждый файл. Я загружаю записи в базу данных из консольного приложения, используя класс SqlBulkCopy, порциями по 5000. Для разделения файлов требуется примерно 30 минут, а для загрузки всего набора данных (более 65 миллионов записей) - примерно 4,5 часа. Сгенерированный размер файла и размер пакетной загрузки являются настройками конфигурации, и я изучаю возможность увеличения их значения для повышения производительности. Для запуска приложения мы используем четырехъядерный сервер с 16 ГБ оперативной памяти. Этот сервер также является сервером базы данных.

Обновление

Учитывая ответы на данный момент, обратите внимание, что до импорта:

  • Таблица базы данных усекается, а все индексы и ограничения удаляются.
  • База данных сжата, а дисковое пространство восстановлено.

После завершения импорта:

  • Индексы воссозданы

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

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

Следующий вопрос может быть полезен для других, имеющих дело с этой проблемой:

Решение

Я исследовал влияние изменения размера пакета и размера разделенных файлов и обнаружил, что пакеты из 500 записей и разделенные файлы из 200 000 записей лучше всего подходят для моего приложения. Использование SqlBulkCopyOptions.TableLock также помогло. См. Ответ на этот вопрос для получения более подробной информации.

Я также рассмотрел использование пакета служб SSIS DTS и сценария BULK INSERT SQL. Пакет служб SSIS появился быстрее, но не дал мне возможности записывать недействительные записи и т. Д. SQL-скрипт BULK INSERT, хотя и медленнее, чем пакет служб SSIS, был значительно быстрее, чем приложение C #. Это позволило мне записывать ошибки и т. Д., И по этой причине я принимаю BULK INSERT ответ от ConcernedOfTunbridgeWells в качестве решения. Я знаю, что это может быть не лучшим ответом для всех, кто сталкивается с этой проблемой, но это отвечает моей непосредственной проблеме.

Спасибо всем, кто ответил.

С уважением, MagicAndi

Ответы [ 11 ]

5 голосов
/ 12 мая 2009

BULK INSERT запускается из самой СУБД, считывая файлы, описанные управляющим файлом bcp, из каталога на сервере (или смонтированного на нем). Напишите приложение, которое разбивает файл на более мелкие куски, помещает их в соответствующий каталог, выполняет оболочку, которая выполняет серию BULK INSERTS. При необходимости вы можете запустить несколько потоков параллельно.

Вероятно, это примерно так же быстро, как и массовая загрузка. Кроме того, если в файле массовой загрузки имеется подходящий ключ разделения, поместите промежуточную таблицу в схему разделения.

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

3 голосов
/ 12 мая 2009

Вы пробовали SSIS (службы интеграции SQL Server).

2 голосов
/ 12 мая 2009

Вы можете сохранить шаг разделения файлов следующим образом:

  • Создание экземпляра IDataReader для чтения значений из входного CSV-файла. Есть несколько способов сделать это: самый простой, вероятно, использовать драйвер Microsoft OleDb Jet. Google для этого, если вам нужно больше информации - например, в этом вопросе StackOverflow есть информация .

    Альтернативный метод - использовать метод, подобный тому, который используется www.csvreader.com .

  • Создание объекта SqlBulkCopy, установка свойств BatchSize и BulkCopyTimeout на соответствующие значения.

  • Передайте IDataReader методу SqlBulkCopy.WriteToServer.

Я успешно использовал эту технику с большими файлами, но не такими большими, как у вас.

2 голосов
/ 12 мая 2009

Класс SqlBulkCopy , который вы уже используете, станет вашим лучшим выбором. Лучшее, что вы можете сделать здесь, в своем коде c #, - это поэкспериментировать с вашей конкретной системой и данными, чтобы увидеть, какие размеры пакетов работают лучше всего. Но ты уже делаешь это.

Выходя за пределы клиентского кода, вы можете сделать несколько вещей с сервером, чтобы сделать импорт более эффективным:

  • Попробуйте установить размер таблицы и базы данных, прежде чем начинать импорт, до чего-то достаточно большого, чтобы вместить весь набор. Вы не хотите полагаться на авто-рост в середине этого.

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

  • Наконец, заманчиво попробовать запустить это параллельно, когда несколько потоков делают массовые вставки одновременно. Однако самое большое узкое место - это почти наверняка производительность диска. Все, что вы можете сделать с физическим сервером для улучшения этого (новые диски, san и т. Д.), Поможет гораздо больше.

1 голос
/ 13 мая 2009

См. это и это сообщения в блоге для сравнения. Кажется, лучшая альтернатива - использовать BulkInsert с параметром TABLOCK, установленным в true.

0 голосов
/ 15 мая 2009

Мой сценарий для таких вещей: Создать пакет служб SSIS на сервере SQL, который с помощью BLUK вставит в SQL, Создайте хранимую процедуру внутри базы данных, чтобы запускать этот пакет из кода T-SQL

После этого отправьте файл для вставки bluk на сервер SQL через FTP и вызовите пакет SSIS с помощью хранимой процедуры

0 голосов
/ 12 мая 2009

Просто чтобы проверить, что ваша вставка будет быстрее, если в таблице, в которую вы вставляете, нет индексов.

0 голосов
/ 12 мая 2009

Вы пробовали службы интеграции SQL Server для этого? Может быть лучше обрабатывать такой большой текстовый файл

0 голосов
/ 12 мая 2009

BULK INSERT, вероятно, уже самый быстрый способ. Вы можете повысить производительность, отбросив индексы и ограничения, одновременно вставляя и восстанавливая их. Наибольшее влияние на производительность оказывают кластерные индексы.

0 голосов
/ 12 мая 2009

В последнее время мне тоже пришлось много загружать / импортировать (встроенный PHP-скрипт).

Я решил обработать их запись для записи.

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

Это всего лишь совет.

С уважением, Бенедикта

...