Delen via


Efficiënt bijwerken

Batchverwerking

EF Core helpt roundtrips te minimaliseren door alle updates in één roundtrip automatisch samen te voegen. Houd rekening met het volgende:

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();

Het bovenstaande laadt een blog uit de database, wijzigt de URL en voegt vervolgens twee nieuwe blogs toe; om dit toe te passen, worden twee SQL INSERT-instructies en één UPDATE-instructie verzonden naar de database. In plaats van ze één voor één te verzenden, houdt EF Core deze wijzigingen intern bij terwijl er blogexemplaren worden toegevoegd, en voert het deze in één verwerkingsronde uit wanneer SaveChanges wordt aangeroepen.

Het aantal instructies dat EF batches in één roundtrip uitvoert, is afhankelijk van de databaseprovider die wordt gebruikt. Een prestatieanalyse heeft bijvoorbeeld aangetoond dat batchverwerking over het algemeen minder efficiënt is voor SQL Server wanneer er minder dan 4 instructies zijn betrokken. Op dezelfde manier worden de voordelen van batchverwerking verminderd na ongeveer 40 instructies voor SQL Server, zodat EF Core standaard slechts maximaal 42 instructies in één batch uitvoert en extra instructies in afzonderlijke roundtrips uitvoert.

Gebruikers kunnen deze drempelwaarden ook aanpassen om mogelijk hogere prestaties te bereiken, maar benchmark zorgvuldig voordat ze deze wijzigen:

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

ExecuteUpdate en ExecuteDelete gebruiken wanneer relevant

Stel dat u al uw werknemers een verhoging wilt geven. Een typische implementatie hiervoor in EF Core ziet er als volgt uit:

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

Hoewel dit een perfect geldige code is, gaan we analyseren wat deze doet vanuit prestatieperspectief:

  • Er wordt een database-ronde uitgevoerd om alle relevante werknemers te laden; let op dat hiermee alle rijgegevens van de werknemers naar de cliënt worden gebracht, zelfs als alleen het salaris nodig is.
  • Met het bijhouden van wijzigingen in EF Core worden momentopnamen gemaakt bij het laden van de entiteiten en worden deze momentopnamen vergeleken met de exemplaren om erachter te komen welke eigenschappen zijn gewijzigd.
  • Normaal gesproken wordt een tweede database-ronde uitgevoerd om alle wijzigingen op te slaan (merk op dat sommige databaseproviders de wijzigingen splitsen in meerdere rondes). Hoewel dit batchgedrag veel beter is dan het uitvoeren van een roundtrip voor elke update, verzendt EF Core nog steeds een UPDATE-instructie per werknemer en moet de database elke instructie afzonderlijk uitvoeren.

Vanaf EF Core 7.0 kunt u de methoden ExecuteUpdateAsync en ExecuteDeleteAsync gebruiken om hetzelfde veel efficiënter te doen:

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

Hiermee wordt de volgende SQL-instructie naar de database verzonden:

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

Deze UPDATE voert de hele bewerking uit in één keer, zonder werkelijke gegevens naar de database in te laden of te verzenden, en zonder gebruik te maken van de mechanismen van EF voor het bijhouden van wijzigingen, wat extra overhead oplevert. Zie ExecuteUpdate en ExecuteDeletevoor meer informatie.

Als u een oudere versie van EF Core gebruikt die nog geen ondersteuning biedt voor ExecuteUpdate en ExecuteDelete, of als u een complexe SQL-instructie wilt uitvoeren die niet wordt ondersteund door deze methoden, kunt u nog steeds een SQL-query gebruiken om de bewerking uit te voeren:

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

Zie de overzichtspagina over het opslaan van gegevens voor meer informatie over de verschillen tussen SaveChanges en ExecuteUpdate/ExecuteDelete.