Zasadniczo wstawiam 35000 obiektów w ramach jednej transakcji:
using(var uow = new MyContext()){
for(int i = 1; i < 35000; i++) {
var o = new MyObject()...;
uow.MySet.Add(o);
}
uow.SaveChanges();
}
To trwa wieczność! Jeśli użyję podstawowego ObjectContex
t (używając IObjectAdapter
), nadal jest powolny, ale zajmuje około 20 sekund. Wygląda na DbSet<>
to, że przeprowadza wyszukiwanie liniowe, które zajmuje kwadratową ilość czasu ...
Czy ktoś jeszcze widzi ten problem?
c#
entity-framework
entity-framework-4.1
Hartmuta
źródło
źródło
Odpowiedzi:
Jak już wskazał Ladislav w komentarzu, musisz wyłączyć automatyczne wykrywanie zmian, aby poprawić wydajność:
context.Configuration.AutoDetectChangesEnabled = false;
To wykrywanie zmian jest domyślnie włączone w
DbContext
interfejsie API.Powodem, dla którego
DbContext
zachowuje się tak inaczej niżObjectContext
API, jest to, że o wiele więcej funkcjiDbContext
API będzie wywoływaćDetectChanges
wewnętrznie niż funkcjeObjectContext
API, gdy włączone jest automatyczne wykrywanie zmian.Tutaj znajdziesz listę tych funkcji, które są wywoływane
DetectChanges
domyślnie. Oni są:Add
,Attach
,Find
,Local
, lubRemove
członków wDbSet
GetValidationErrors
,Entry
lubSaveChanges
wDbContext
Entries
Metoda naDbChangeTracker
Szczególnie
Add
połączenia,DetectChanges
które są odpowiedzialne za słabą wydajność, jakiej doświadczyłeś.W przeciwieństwie do tego
ObjectContext
API wywołujeDetectChanges
tylko automatycznie,SaveChanges
ale nie w,AddObject
i inne odpowiednie metody wymienione powyżej. To jest powód, dla którego domyślna wydajnośćObjectContext
jest szybsza.Dlaczego wprowadzili to domyślne automatyczne wykrywanie zmian
DbContext
w tak wielu funkcjach? Nie jestem pewien, ale wydaje się, że wyłączenie go iDetectChanges
ręczne wywoływanie we właściwych punktach jest uważane za zaawansowane i może łatwo wprowadzić subtelne błędy do twojej aplikacji, więc używaj go ostrożnie .źródło
Mały test empiryczny z EF 4.3 CodeFirst:
Usunięto 1000 obiektów z AutoDetectChanges = true: 23 sek
Usunięto 1000 obiektów z AutoDetectChanges = false: 11 sek
Wstawiono 1000 obiektów z AutoDetectChanges = true: 21 sek
Wstawiono 1000 obiektów z AutoDetectChanges = false: 13 sek
źródło
W .netcore 2.0 zostało to przeniesione do:
context.ChangeTracker.AutoDetectChangesEnabled = false;
źródło
Oprócz odpowiedzi, które znalazłeś tutaj. Ważne jest, aby wiedzieć, że na poziomie bazy danych więcej pracy trzeba wstawić niż dodać. Baza danych musi rozszerzyć / przydzielić nowe miejsce. Następnie musi zaktualizować przynajmniej indeks klucza podstawowego. Chociaż indeksy mogą być również aktualizowane podczas aktualizacji, jest to znacznie mniej powszechne. Jeśli są jakieś klucze obce, musi również odczytać te indeksy, aby zapewnić zachowanie integralności referencyjnej. Wyzwalacze również mogą odgrywać rolę, chociaż mogą wpływać na aktualizacje w ten sam sposób.
Cała ta praca z bazą danych ma sens w codziennej czynności wstawiania zapoczątkowanej przez wpisy użytkowników. Ale jeśli po prostu przesyłasz istniejącą bazę danych lub masz proces, który generuje wiele wstawek. Możesz spojrzeć na sposoby na przyspieszenie tego, odkładając to na koniec. Zwykle wyłączanie indeksów podczas wstawiania jest powszechnym sposobem. Istnieją bardzo złożone optymalizacje, które można wykonać w zależności od przypadku, mogą one być nieco przytłaczające.
Po prostu wiedz, że generalnie wstawianie zajmie więcej czasu niż aktualizacje.
źródło