В основном я вставляю 35000 объектов в одну транзакцию:
using(var uow = new MyContext()){
for(int i = 1; i < 35000; i++) {
var o = new MyObject()...;
uow.MySet.Add(o);
}
uow.SaveChanges();
}
Это займет вечность! Если я использую базовый ObjectContex
t (с помощью IObjectAdapter
), он все равно медленный, но занимает около 20 секунд. Это выглядит какDbSet<>
выполняется линейный поиск, на который требуется определенное количество времени ...
Кто-нибудь еще видит эту проблему?
Ответы:
Как уже указал Ладислав в комментарии, вам нужно отключить автоматическое обнаружение изменений для повышения производительности:
context.Configuration.AutoDetectChangesEnabled = false;
Это обнаружение изменений включено по умолчанию в
DbContext
API.Причина, по которой
DbContext
поведение так отличается отObjectContext
API, заключается в том, что гораздо больше функцийDbContext
API будет вызыватьDetectChanges
внутренние функции, чем функцииObjectContext
при включенном автоматическом обнаружении изменений API.Здесь вы можете найти список тех функций, которые вызываются
DetectChanges
по умолчанию. Они есть:Add
,Attach
,Find
,Local
, илиRemove
члены наDbSet
GetValidationErrors
,Entry
илиSaveChanges
наDbContext
Entries
Способ поDbChangeTracker
Особенно
Add
звонки,DetectChanges
которые являются причиной плохой работы, с которой вы столкнулись.Я контрастирую с этим,
ObjectContext
API вызываетDetectChanges
только автоматически,SaveChanges
но не вAddObject
других соответствующих методах, упомянутых выше. Вот причина , почему по умолчанию производительностьObjectContext
быстрее.Почему они ввели автоматическое обнаружение изменений по умолчанию в
DbContext
во многих функциях? Я не уверен, но кажется, что его отключение и вызовDetectChanges
вручную в нужных точках считается продвинутым и может легко внести небольшие ошибки в ваше приложение, поэтому используйте [его] с осторожностью .источник
Небольшой эмпирический тест с EF 4.3 CodeFirst:
Удалено 1000 объектов с AutoDetectChanges = true: 23 сек.
Удалено 1000 объектов с AutoDetectChanges = false: 11 сек.
Вставлено 1000 объектов с AutoDetectChanges = true: 21 сек.
Вставлено 1000 объектов с AutoDetectChanges = false: 13 сек.
источник
В .netcore 2.0 это было перемещено в:
context.ChangeTracker.AutoDetectChangesEnabled = false;
источник
Помимо ответов, которые вы нашли здесь. Важно знать, что на уровне базы данных больше работы по вставке, чем по добавлению. База данных должна расширить / выделить новое пространство. Затем он должен обновить хотя бы индекс первичного ключа. Хотя индексы также могут обновляться при обновлении, это происходит гораздо реже. Если есть какие-либо внешние ключи, он должен прочитать и эти индексы, чтобы убедиться, что ссылочная целостность сохраняется. Триггеры также могут играть роль, хотя они могут одинаково влиять на обновления.
Вся эта работа с базой данных имеет смысл в ежедневной активности вставки, инициированной пользовательскими записями. Но если вы просто загружаете существующую базу данных или имеете процесс, который генерирует много вставок. Вы можете найти способы ускорить это, отложив это до конца. Обычно отключение индексов во время вставки является обычным способом. Есть очень сложные оптимизации, которые могут быть выполнены в зависимости от случая, они могут быть немного утомительными.
Просто знайте, что в целом вставка занимает больше времени, чем обновления.
источник