SaveChanges eines Entity Framework-Kontextes ist gerade bei vielen Änderungen oder vielen Inserts sehr langsam. Dieser Artikel zeigt Optimierungsmöglichkeiten auf.

Ich setze das Entity Framework 6 nur ganz selten ein. In einem aktuellen Projekt mussten viele Daten einmalig importiert werden und das Datenbankschema stand bereits fest. Ergo dachte ich mir, ich setze auf EF, generiere mir das Modell, parse die Daten (Anlieferung per JSON) und schreibe sie in die Datenbank.

Die Lösung war super schnell implementiert. Den ersten Importversuch habe ich nach 20 Minuten abgebrochen. Hochgerechnet hätte er an die 5-6 Stunden benötigt. Gut, immerhin sind es 6 Tabellen, die Beziehungen zueinander pflegen und einige Millionen Datensätze. Dennoch, das muss viel schneller gehen.

Detect Changes

Besonders großen Einfluss hat die Einstellung (context ist hier der verwendete DbContext)

context.Configuration.AutoDetectChangesEnabled = false;

Damit wird nicht auf etwaige Änderungen geprüft (d.h. kein Lesen von Daten und keine Prüfungen).

Context verwerfen

SaveChanges habe ich nur einmal nachdem ich alle Daten dem Kontext hinzugefügt hatte, aufgerufen. Das führte bei mir zu einer OutOfMemoryException. Daher habe ich das in kleinere Chunks unterteilt und dafür dann SaveChanges aufgerufen. Es empfiehlt sich dann, den Kontext zu verwerfen und neu zu erstellen. Dadurch wird dieser bereinigt und enthält keine Daten mehr. Umso mehr Daten dieser enthält, umso langsamer wird er:

context.Dispose();
context = new MyDbContext();
context.Configuration.AutoDetectChagnesEnabled = false;

Änderungen asynchron speichern

Eine besonders große Änderung hat dann folgende Verwendung gebracht:

context.SaveChangesAsync().Wait();

Dadurch werden die Änderungen asynchron in die Datenbank übertragen (sofern möglich), was natürlich eine gewaltige Menge an Zeit spart.

Fazit

Durch die gezeigten Verbesserungsmöglichkeiten konnte ich die Verarbeitungszeit auf knapp 10 Minuten reduzieren. Wer es noch schneller braucht, der solle auf ein Bulk-Insert umsteigen, muss dafür allerdings mehr implementieren. Für meinen Fall war es so ausreichend. Gutes

Über den Autor

Norbert Eder

Ich bin ein leidenschaftlicher Softwareentwickler und Fotograf. Mein Wissen und meine Gedanken teile ich nicht nur hier im Blog, sondern auch in Fachartikeln und Büchern.

1 Kommentar

  • SaveChangesAsync gibt doch wahrscheinlich einen Task zurück oder?
    Warum blockst du stattdessen den Thread anstatt cooperative zu awaiten?

Hinterlasse einen Kommentar