2009-06-10 7 views
4

У нас есть небольшой инструмент C#, который мы собрали вместе, чтобы проанализировать файл данных, создать некоторые объекты и вставить их в БД.Использование LINQ2SQL для вставки большого количества записей

Логика по существу.

string [] lines = File.ReadAllLines("C:\\Temp\\Data.dat") 

foreach(string line in lines) 
{ 
    MyDataObject obj = ParseObject(line); 
    myDataContext.MyDataObjects.InsertOnSubmit(obj); 
} 

myDataContext.SubmitChanges(); 

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

Все до SubmitChanges() звонок прекрасен, но как только он начинает процесс сброса 30 000 вставок в БД, он просто останавливается. В качестве теста я фикционировал 30 000 заявлений вставки и запускал их непосредственно из QA. Это заняло примерно 8 минут.

Спустя 8 минут версия C#/Linq выполнила только около 25% вставок.

У кого-нибудь есть предложения, как я могу оптимизировать это?

ответ

6

Если вы пишете большой объем однородных данных, SqlBulkCopy может быть более подходящим инструментом , например, возможно, с CsvReader для чтения строк (поскольку SqlBulkCopy может принимать IDataReader, что означает, что вам не нужно буферизовать все 30k строк в память).

Если данные в формате CSV, это может быть столь же просто, как:

using (CsvReader reader = new CsvReader(path)) 
using (SqlBulkCopy bcp = new SqlBulkCopy(CONNECTION_STRING)) 
{ 
    bcp.DestinationTableName = "SomeTable"; 
    bcp.WriteToServer(reader); 
} 

Если данные более сложным (не-CSV), то SimpleDataReader может быть полезным - вы просто подкласс и добавить код для представления ваших данных в строке.

+0

Cheers Marc, пошли по этому маршруту, создав DataTable в памяти и передав его объекту BulkCopy. это не плоский CSV, к сожалению, и ему необходимо много манипулировать, прежде чем вставлять его на сервер. Спасибо –

1

У меня был тот же вопрос некоторое время назад. Я вставлял 1000000 новых записей в db, и я обнаружил, что tat вызывает SubmitChanges, каждый из 500 был самым быстрым способом.

Я не могу гарантировать, что 500 строк в то время это самый быстрый, наша среда довольно странно ...

+3

Я подозреваю, что это связано с максимальным количеством параметров, которые может содержать одна команда SQL. Я считаю, что максимум 2100 параметров. Если бы вы вставляли записи с 4 столбцами, оптимальным было бы около 500. – Thorarin

+0

На самом деле у моего запроса было 4 параметра! Спасибо за подсказку !!! –

1

Возможно, вы захотите попробовать многопоточный подход.

  1. Partition рекорд, установленный в меньших размерах (1000 каждый?), Поместить их в стек
  2. Есть класс, который будет захватывать рекорд, установленный в верхней части стека и начать, чтобы вставить его с помощью нескольких класс, который открывает DataContext и вставляет его самостоятельно.
  3. Хотя это вставка, второй класс открыт для следующего набора записей
  4. Внутренняя логика диктует, сколько вставки могут быть запущены одновременно (5? 10?)

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

1

Это задача базы данных, которая должна выполняться через SSIS и использовать объемную вставку.

Я могу вставить 30 000 записей за считанные секунды или миллисекунды (в зависимости от количества столбцов и сложности отображения данных).У меня есть импорт с более чем миллионом записей, которые вставляются за меньшее время, чем вы тратите цикл по записям по одному. У меня даже есть один 20-миллионный файл записи, который занимает всего 16 минут.

+0

Да, это здорово. Однако это невозможно. Для начала это на SQL 2000, так что нет ssis, это DTS-территория. Во-вторых, данные поступают от филиала в наш бизнес-отдел. и я вполне доволен тем, что предоставил им инструмент, который занимает 2 минуты, чтобы загружать данные, вместо того, чтобы предоставлять им полный доступ к БД, чтобы они могли гадоваться с менеджером предприятия. –

+0

Вы можете сделать это с помощью DTS. Затем попросите приложение вызвать пакет DTS. Или сделайте это в хранимой процедуре с использованием массовой вставки и попросите приложение вызвать proc. – HLGEM

0

Старый вопрос, но после поиска моего решения я наткнулся на this code project article, который отлично. В основном использует атрибуты Linq2Sql для создания DataTable, а затем использует SQLBulkCopy для вставки, который был намного быстрее, чем базовая реализация Linq2Sql. Код в статье мог бы использовать немного очистки и может упасть на более сложные сценарии с внешними ключами (у меня не было в моей модели, хотя было в БД), но отлично соответствовало моим потребностям.

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