Как я могу ускорить DbSet.Add ()? - PullRequest
30 голосов
/ 04 декабря 2010

Мне нужно импортировать около 30 тыс. Строк из файла CSV в базу данных SQL, к сожалению, это занимает 20 минут.

Устранение неполадок с помощью профилировщика показывает, что DbSet.Add занимает больше всего времени, но почему?

У меня есть следующие классы Entity Framework Code-First:

public class Article
{
    // About 20 properties, each property doesn't store excessive amounts of data
}

public class Database : DbContext
{
    public DbSet<Article> Articles { get; set; }
}

Для каждого элемента моего цикла for:

db.Articles.Add(article);

Вне цикла for я делаю:

db.SaveChanges();

Он связан с моим локальным сервером SQLExpress, но я думаю, что ничего не написано, пока не будет вызван SaveChanges, поэтому я думаю, что сервер не будет проблемой ....

Ответы [ 5 ]

46 голосов
/ 12 июля 2011

Согласно комментарию Кевина Рамена (29 марта) Я могу подтвердить, что настройка db.Configuration.AutoDetectChangesEnabled = false имеет огромное значение для скорости

Запуск Add() для 2324 элементов по умолчанию выполнялся на моей машине 3 минуты 15 секунд, отключение автоопределения привело к завершению операции через 0,5 секунды.

http://blog.larud.net/archive/2011/07/12/bulk-load-items-to-a-ef-4-1-code-first-aspx

19 голосов
/ 17 октября 2012

Я собираюсь добавить к комментарию Кервина Рамена, сказав, что если вы только делаете вставки (не обновляете и не удаляете), то, в общем, вы можете безопасно установить следующие свойства перед выполнением любых вставок в контексте:*

DbContext.Configuration.AutoDetectChangesEnabled = false;
DbContext.Configuration.ValidateOnSaveEnabled = false;

У меня была проблема с однократным массовым импортом на моей работе.Без настройки вышеуказанных свойств добавление в контекст около 7500 сложных объектов заняло более 30 минут.Установка вышеуказанных свойств (таким образом, отключение проверок EF и отслеживание изменений) сократила импорт до секунд.

Но, опять же, я подчеркиваю, используйте это, только если вы делаете вставки.Если вам нужно смешать вставки с обновлениями / удалениями, вы можете разбить код на два пути и отключить проверки EF для вставки, а затем снова включить проверки для пути обновления / удаления.Я успешно использовал этот подход, чтобы обойти медленное DbSet.Add() поведение.

9 голосов
/ 04 декабря 2010

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

Первое, что я бы попробовал, это группировать, скажем, группы по 500 (меняйте это число в соответствии с потребностями), начиная с нового (нового) объектного контекста каждый раз - иначе вы можете разумно ожидать производительность телескопирования. Разбиение его на партии также предотвращает мегалитическую транзакцию, которая останавливает все.

Помимо этого; SqlBulkCopy. Он рассчитан на крупный импорт с минимальными накладными расходами. Это не EF, хотя.

5 голосов
/ 10 июня 2014

Здесь очень простое в использовании и очень быстрое расширение: https://efbulkinsert.codeplex.com/

Это называется «Массовая вставка Entity Framework».

Само расширение находится в пространстве имен EntityFramework.BulkInsert.Extensions. Таким образом, чтобы раскрыть метод расширения, добавьте

using EntityFramework.BulkInsert.Extensions;

И тогда вы можете сделать это

context.BulkInsert(entities);

Кстати, если вы не хотите использовать это расширение по какой-либо причине, вы можете попробовать вместо запуска db.Articles.Add (article) для каждой статьи каждый раз создавать список из нескольких статей и затем использовать AddRange (впервые в EF версии 6, вместе с RemoveRange), чтобы добавить их вместе в dbcontext.

1 голос
/ 24 декабря 2010

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

Для первой части попробуйте: http://www.c -sharpcorner.com / UploadFile / Махеш / AccessTextDb12052005071306AM / AccessTextDb.aspx

Для второй части попробуйте это для процедуры SQL: http://www.builderau.com.au/program/sqlserver/soa/Passing-table-valued-parameters-in-SQL-Server-2008/0,339028455,339282577,00.htm

И создайте объект SqlCommnand в c # и добавьте в его коллекцию Parameters SqlParameter SqlDbType.Structured

Что ж, надеюсь, это поможет.

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