it-swarm.com.de

Warum ist das Einfügen von Objekten in EF 4.1 im Vergleich zu ObjectContext so langsam?

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 ObjectContext verwende (indem ich IObjectAdapter verwende), ist es immer noch langsam, dauert aber ungefähr 20s. Es sieht aus wie DbSet<> führt einige lineare Suchvorgänge durch, die eine quadratische Menge an Zeit in Anspruch nehmen ...

Hat noch jemand dieses Problem gesehen?

79
Hartmut

Wie bereits von Ladislav im Kommentar angegeben, müssen Sie die automatische Änderungserkennung deaktivieren, um die Leistung zu verbessern:

context.Configuration.AutoDetectChangesEnabled = false;

Diese Änderungserkennung ist standardmäßig in der API DbContext aktiviert.

Der Grund, warum sich DbContext so unterschiedlich zur ObjectContext-API verhält, ist, dass viel mehr Funktionen der DbContext-API DetectChanges intern aufrufen als Funktionen der ObjectContext API, wenn die automatische Änderungserkennung aktiviert ist.

Hier finden Sie eine Liste der Funktionen, die standardmäßig DetectChanges aufrufen. Sie sind:

  • Die Add, Attach, Find, Local oder Remove Mitglieder in DbSet
  • Die GetValidationErrors, Entry oder SaveChanges Mitglieder in DbContext
  • Die Entries Methode für DbChangeTracker

Insbesondere Add ruft DetectChanges auf, was für die schlechte Leistung verantwortlich ist, die Sie erlebt haben.

Im Gegensatz dazu ruft die ObjectContext -API DetectChanges nur automatisch in SaveChanges auf, nicht jedoch in AddObject und den anderen oben erwähnten entsprechenden Methoden. Das ist der Grund, warum die Standardleistung von ObjectContext schneller ist.

Warum haben sie diese standardmäßige automatische Änderungserkennung in DbContext in so vielen Funktionen eingeführt? Ich bin nicht sicher, aber es scheint, dass das Deaktivieren und das manuelle Aufrufen von DetectChanges an den richtigen Stellen als fortgeschritten betrachtet wird und leicht subtile Fehler in Ihre Anwendung einbringen kann, also verwenden Sie [it] with Pflege .

124
Slauma

Kleiner empirischer Test mit EF 4.3 CodeFirst:

Entfernte 1000 Objekte mit AutoDetectChanges = true: 23 sec

Entfernte 1000 Objekte mit AutoDetectChanges = false: 11 Sek

1000 Objekte mit AutoDetectChanges eingefügt = true: 21 sek

1000 Objekte mit AutoDetectChanges = false eingefügt: 13 Sek

11
Zax

In .netcore 2.0 wurde dies verschoben nach:

context.ChangeTracker.AutoDetectChangesEnabled = false;

4
Maxvt

Neben den Antworten, die Sie hier gefunden haben. 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. Auch wenn Indizes beim Aktualisieren möglicherweise aktualisiert werden, ist dies weitaus seltener der Fall. Wenn Fremdschlüssel vorhanden sind, müssen auch diese Indizes gelesen werden, um sicherzustellen, dass die referenzielle Integrität erhalten bleibt. Trigger können ebenfalls eine Rolle spielen, auch wenn sie Updates auf die gleiche Weise beeinflussen können.

All diese Datenbankarbeit ist bei täglichen Einfügeaktivitäten sinnvoll, die von Benutzereingaben stammen. Wenn Sie jedoch 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 während des Einfügens eine übliche Methode. Es gibt sehr komplexe Optimierungen, die je nach Fall durchgeführt werden können, sie können etwas überwältigend sein.

Wisse nur, dass das Einfügen im Allgemeinen länger dauert als das Aktualisieren.

1