Использование LINQ2SQL для вставки большого количества записей - PullRequest
4 голосов
/ 10 июня 2009

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

Логика по сути.

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

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

myDataContext.SubmitChanges();

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

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

Через 8 минут версия C # / Linq завершила только около 25% операций вставки.

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

Ответы [ 5 ]

6 голосов
/ 10 июня 2009

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

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

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

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

1 голос
/ 10 июня 2009

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

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

1 голос
/ 10 июня 2009

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

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

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

1 голос
/ 10 июня 2009

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

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

0 голосов
/ 24 июля 2013

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

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