Grundsätzlich füge ich 35000 Objekte in eine Transaktion ein:
using(var uow = new MyContext()){
for(int i = 1; i < 35000; i++) {
var o = new MyObject()...;
uow.MySet.Add(o);
}
uow.SaveChanges();
}
Das dauert ewig! Wenn ich das zugrunde liegende ObjectContex
t verwende (indem ich es verwende IObjectAdapter
), ist es immer noch langsam, dauert aber ungefähr 20 Sekunden. Es sieht so aus, DbSet<>
als würde man einige lineare Suchen durchführen, was sehr viel Zeit in Anspruch nimmt ...
Hat noch jemand dieses Problem gesehen?
c#
entity-framework
entity-framework-4.1
Hartmut
quelle
quelle
Antworten:
Wie bereits von Ladislav im Kommentar angegeben, müssen Sie die automatische Änderungserkennung deaktivieren, um die Leistung zu verbessern:
Diese Änderungserkennung ist in der
DbContext
API standardmäßig aktiviert .Der Grund, warum
DbContext
sich dasObjectContext
Verhalten von der API so unterscheidet, ist, dass viel mehr Funktionen derDbContext
APIDetectChanges
intern aufgerufen werden als Funktionen derObjectContext
API, wenn die automatische Änderungserkennung aktiviert ist.Hier finden Sie eine Liste der Funktionen, die
DetectChanges
standardmäßig aufgerufen werden. Sie sind:Add
,Attach
,Find
,Local
, oderRemove
Mitglieder aufDbSet
GetValidationErrors
,Entry
oderSaveChanges
Mitglieder aufDbContext
Entries
Methode aufDbChangeTracker
Besonders
Add
Anrufe,DetectChanges
die für die schlechte Leistung verantwortlich sind, die Sie erlebt haben.Im Gegensatz dazu
ObjectContext
ruft die APIDetectChanges
nur automatisch in,SaveChanges
aber nicht inAddObject
und den anderen oben genannten entsprechenden Methoden auf. Dies ist der Grund, warum die Standardleistung vonObjectContext
schneller ist.Warum haben sie diese standardmäßige automatische Änderungserkennung
DbContext
in so vielen Funktionen eingeführt? Ich bin mir nicht sicher, aber es scheint, dass das Deaktivieren undDetectChanges
manuelle Aufrufen an den richtigen Stellen als fortgeschritten angesehen wird und leicht subtile Fehler in Ihre Anwendung einbringen kann. Verwenden Sie [es] daher mit Vorsicht .quelle
Kleiner empirischer Test mit EF 4.3 CodeFirst:
1000 Objekte mit AutoDetectChanges = true entfernt: 23 Sek
1000 Objekte mit AutoDetectChanges = false entfernt: 11 Sek
1000 Objekte mit AutoDetectChanges = true eingefügt: 21 Sek
1000 Objekte mit AutoDetectChanges = false eingefügt: 13 Sek
quelle
In .netcore 2.0 wurde dies verschoben zu:
context.ChangeTracker.AutoDetectChangesEnabled = false;
quelle
Neben den Antworten haben Sie hier gefunden. Es ist wichtig zu wissen, dass auf Datenbankebene mehr Arbeit zum Einfügen als zum Hinzufügen erforderlich ist. Die Datenbank muss neuen Speicherplatz erweitern / zuweisen. Dann muss mindestens der Primärschlüsselindex aktualisiert werden. Obwohl Indizes beim Aktualisieren möglicherweise auch aktualisiert werden, ist dies weitaus seltener. Wenn Fremdschlüssel vorhanden sind, müssen diese Indizes ebenfalls gelesen werden, um sicherzustellen, dass die referenzielle Integrität erhalten bleibt. Trigger können ebenfalls eine Rolle spielen, obwohl diese Updates auf die gleiche Weise beeinflussen können.
All diese Datenbankarbeit ist bei täglichen Einfügetätigkeiten sinnvoll, die durch Benutzereingaben entstehen. Aber wenn Sie nur eine vorhandene Datenbank hochladen oder einen Prozess haben, der viele Einfügungen generiert. Vielleicht möchten Sie nach Möglichkeiten suchen, dies zu beschleunigen, indem Sie es auf das Ende verschieben. Normalerweise ist das Deaktivieren von Indizes beim Einfügen üblich. Es gibt sehr komplexe Optimierungen, die je nach Fall durchgeführt werden können, sie können etwas überwältigend sein.
Beachten Sie nur, dass das Einfügen im Allgemeinen länger dauert als Aktualisierungen.
quelle