Freigeben über


Effiziente Aktualisierung

Batchverarbeitung

EF Core trägt dazu bei, Roundtrips zu minimieren, indem es alle Updates automatisch in einem einzigen Roundtrip zusammenfasst. Beachten Sie Folgendes:

var blog = await context.Blogs.SingleAsync(b => b.Url == "http://someblog.microsoft.com");
blog.Url = "http://someotherblog.microsoft.com";
context.Add(new Blog { Url = "http://newblog1.microsoft.com" });
context.Add(new Blog { Url = "http://newblog2.microsoft.com" });
await context.SaveChangesAsync();

Im Obigen wird ein Blog aus der Datenbank geladen, seine URL geändert und dann zwei neue Blogs hinzugefügt. um dies anzuwenden, werden zwei SQL INSERT-Anweisungen und eine UPDATE-Anweisung an die Datenbank gesendet. Anstatt sie nacheinander zu senden, wenn Blog-Instanzen hinzugefügt werden, verfolgt EF Core diese Änderungen intern und führt sie in einem einzigen Roundtrip aus, wenn SaveChanges aufgerufen wird.

Die Anzahl der Anweisungen, die EF in einem einzelnen Roundtrip als Batch zusammenfasst, hängt vom verwendeten Datenbankanbieter ab. Die Leistungsanalyse hat beispielsweise gezeigt, dass die Batchverarbeitung in der Regel weniger effizient für SQL Server ist, wenn weniger als 4 Anweisungen beteiligt sind. Ebenso lässt der Nutzen der Batchverarbeitung bei SQL Server nach etwa 40 Anweisungen nach, so dass EF Core standardmäßig nur bis zu 42 Anweisungen in einem einzigen Batch ausführt und weitere Anweisungen in separaten Roundtrips ausführt.

Benutzer können diese Schwellenwerte auch optimieren, um eine potenziell höhere Leistung zu erzielen . Führen Sie jedoch eine sorgfältige Benchmark durch, bevor Sie diese ändern:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseSqlServer(
        @"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True",
        o => o
            .MinBatchSize(1)
            .MaxBatchSize(100));
}

Verwenden Sie ExecuteUpdate und ExecuteDelete, wenn relevant.

Nehmen wir an, Sie möchten allen Ihren Mitarbeitern eine Erhöhung geben. Eine typische Implementierung für dies in EF Core würde wie folgt aussehen:

foreach (var employee in context.Employees)
{
    employee.Salary += 1000;
}
await context.SaveChangesAsync();

Dies ist zwar perfekt gültiger Code, lassen Sie uns jedoch analysieren, was es aus Leistungsperspektive tut:

  • Es wird ein Datenbank-Roundtrip durchgeführt, um alle relevanten Mitarbeitenden zu laden. Beachten Sie, dass dadurch alle Zeilendaten der Mitarbeitenden zum Client gelangen, auch wenn nur das Gehalt benötigt wird.
  • Die Änderungsnachverfolgung von EF Core erstellt Momentaufnahmen beim Laden der Entitäten und vergleicht diese Momentaufnahmen dann mit den Instanzen, um herauszufinden, welche Eigenschaften geändert wurden.
  • In der Regel wird ein zweiter Datenbank-Roundtrip ausgeführt, um alle Änderungen zu speichern (beachten Sie, dass einige Datenbankanbieter die Änderungen in mehrere Roundtrips aufteilen). Obwohl dieses Batchverarbeitungsverhalten wesentlich besser ist als ein Roundtrip für jede Aktualisierung, sendet EF Core weiterhin eine UPDATE-Anweisung pro mitarbeitende Person, und die Datenbank muss jede Anweisung separat ausführen.

Ab EF Core 7.0 können Sie die ExecuteUpdateAsync und ExecuteDeleteAsync Methoden verwenden, um dasselbe wesentlich effizienter zu erledigen:

await context.Employees.ExecuteUpdateAsync(s => s.SetProperty(e => e.Salary, e => e.Salary + 1000));

Dadurch wird die folgende SQL-Anweisung an die Datenbank gesendet:

UPDATE [Employees] SET [Salary] = [Salary] + 1000;

Dieses UPDATE führt den gesamten Vorgang in einem einzelnen Roundtrip aus, ohne tatsächliche Daten in die Datenbank zu laden oder zu ihr zu senden, und ohne die EF-Funktionen zur Änderungsnachverfolgung zu nutzen, die einen zusätzlichen Aufwand verursachen. Weitere Informationen finden Sie unter ExecuteUpdate und ExecuteDelete.

Wenn Sie eine ältere Version von EF Core verwenden, die noch keine ExecuteUpdate und ExecuteDeleteunterstützt oder eine komplexe SQL-Anweisung ausführen möchten, die von diesen Methoden nicht unterstützt wird, können Sie weiterhin eine SQL-Abfrage verwenden, um den Vorgang auszuführen:

context.Database.ExecuteSql($"UPDATE [Employees] SET [Salary] = [Salary] + 1000");

Weitere Informationen zu den Unterschieden zwischen SaveChanges und ExecuteUpdate/ExecuteDeletefinden Sie auf der Übersichtsseite über das Speichern von Daten.