Zu Ihrer Bemerkung in den Kommentaren zu Ihrer Frage:
"...SavingChanges ( für jeden Datensatz )..."
Das ist das Schlimmste, was man tun kann! Aufruf von SaveChanges()
für jeden Datensatz verlangsamt Masseneinfügungen extrem. Ich würde ein paar einfache Tests durchführen, die sehr wahrscheinlich die Leistung verbessern werden:
- Rufen Sie an.
SaveChanges()
einmal nach ALLEN Datensätzen.
- Rufen Sie an.
SaveChanges()
nach zum Beispiel 100 Datensätzen.
- Rufen Sie an.
SaveChanges()
nach z.B. 100 Datensätzen und entsorgen den Kontext und erstellen einen neuen.
- Änderungserkennung deaktivieren
Für Masseneinlagen arbeite und experimentiere ich mit einem Muster wie diesem:
using (TransactionScope scope = new TransactionScope())
{
MyDbContext context = null;
try
{
context = new MyDbContext();
context.Configuration.AutoDetectChangesEnabled = false;
int count = 0;
foreach (var entityToInsert in someCollectionOfEntitiesToInsert)
{
++count;
context = AddToContext(context, entityToInsert, count, 100, true);
}
context.SaveChanges();
}
finally
{
if (context != null)
context.Dispose();
}
scope.Complete();
}
private MyDbContext AddToContext(MyDbContext context,
Entity entity, int count, int commitCount, bool recreateContext)
{
context.Set<Entity>().Add(entity);
if (count % commitCount == 0)
{
context.SaveChanges();
if (recreateContext)
{
context.Dispose();
context = new MyDbContext();
context.Configuration.AutoDetectChangesEnabled = false;
}
}
return context;
}
Ich habe ein Testprogramm, das 560.000 Entitäten (9 skalare Eigenschaften, keine Navigationseigenschaften) in die DB einfügt. Mit diesem Code funktioniert es in weniger als 3 Minuten.
Für die Performance ist es wichtig, die SaveChanges()
nach "vielen" Datensätzen ("viele" etwa 100 oder 1000). Es verbessert auch die Leistung, den Kontext nach SaveChanges zu entsorgen und einen neuen zu erstellen. Dies löscht den Kontext von allen Entitäten, SaveChanges
das nicht tut, sind die Entitäten immer noch mit dem Kontext im Zustand Unchanged
. Es ist die wachsende Größe der angehängten Entitäten im Kontext, die das Einfügen Schritt für Schritt verlangsamt. Daher ist es hilfreich, sie nach einiger Zeit zu löschen.
Hier sind ein paar Messungen für meine 560000 Einheiten:
- commitCount = 1, recreateContext = false: viele Stunden (Das ist Ihr derzeitiges Verfahren)
- commitCount = 100, recreateContext = false: mehr als 20 Minuten
- commitCount = 1000, recreateContext = false: 242 sec
- commitCount = 10000, recreateContext = false: 202 Sekunden
- commitCount = 100000, recreateContext = false: 199 sec
- commitCount = 1000000, recreateContext = false: Ausnahme wegen Speichermangels
- commitCount = 1, recreateContext = true: mehr als 10 Minuten
- commitCount = 10, recreateContext = true: 241 sec
- commitCount = 100, recreateContext = true: 164 sec
- commitCount = 1000, recreateContext = true: 191 sec
Der erste Test zeigt, dass die Leistung nicht linear ist und mit der Zeit extrem abnimmt. ("Viele Stunden" ist eine Schätzung, ich habe diesen Test nie beendet, ich habe nach 20 Minuten bei 50.000 Entitäten aufgehört). Dieses nichtlineare Verhalten ist bei allen anderen Tests nicht so signifikant.
2 Stimmen
Wie machen Sie es derzeit?
1 Stimmen
Erstellen des TransactionScope, Instanziierung des DBContext, Öffnen der Verbindung, und in einer for-each-Anweisung die Einfügungen und SavingChanges (für jeden Datensatz), HINWEIS: TransactionScope und DBContext sind in using-Anweisungen, und ich schließe die Verbindung in einem finally-Block
1 Stimmen
Eine weitere Antwort als Referenz: stackoverflow.com/questions/5798646/
1 Stimmen
Wenn Sie AutoDetectChangesEnabled auf false setzen, könnte sich dies negativ auf Anwendungen auswirken, die stark von Steuerelementen von Drittanbietern abhängen. Das sollten Sie bedenken, bevor Sie überstürzt handeln und andere Teile der Anwendung beschädigen.
1 Stimmen
Tolle Lösungen können hier für eine der grundlegenden Web-Aufgaben gesehen werden - Persistieren eines Arrays von Zeilen mit data.... Erstaunliches Framework...
4 Stimmen
Die schnellste Art des Einfügens in eine SQL-Datenbank betrifft nicht EF. AFAIK Its BCP then TVP+Merge/insert.
6 Stimmen
Für diejenigen, die Kommentare lesen werden: Höchst zutreffend, modern 回答 ist hier.
1 Stimmen
Schauen Sie hier ben-morris.com/optimising-bulk-inserts-with-entity-framework-6 außerdem