Sdílet prostřednictvím


Efektivní aktualizace

Dávkování

EF Core pomáhá minimalizovat počet cest tam a zpět tím, že automaticky seskupí všechny aktualizace v rámci jediné cesty tam a zpět. Vezměte v úvahu následující skutečnosti:

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

Výše uvedené načte blog z databáze, změní jeho adresu URL a pak přidá dva nové blogy; k použití tohoto příkazu se do databáze odešlou dva příkazy SQL INSERT a jeden příkaz UPDATE. Místo toho, aby se instance blogu přidávaly jedna po druhé, EF Core tyto změny interně sleduje a provede je v jednom průchodu, když je volán SaveChanges.

Počet příkazů, které EF zpracovává v jednom cyklu cesty tam a zpět, závisí na poskytovateli databáze, který se používá. Například analýza výkonu ukázala, že dávkování je pro SQL Server obecně méně efektivní, když se jedná o méně než 4 příkazy. Podobně se přínosy dávkování snižují po přibližně 40 příkazech pro SQL Server, takže EF Core ve výchozím nastavení spustí až 42 příkazů v jedné dávce a další příkazy provede v samostatných cyklech.

Uživatelé také můžou tyto prahové hodnoty upravit, aby dosáhli potenciálně vyššího výkonu, ale před úpravou těchto hodnot pečlivě proveďte srovnávací testy:

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

Použití ExecuteUpdate a ExecuteDelete, pokud jsou relevantní

Předpokládejme, že chcete všem svým zaměstnancům dát zvýšení. Typická implementace pro tuto implementaci v EF Core by vypadala takto:

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

I když je to dokonale platný kód, pojďme analyzovat, co dělá z hlediska výkonu:

  • Provede se dotaz do databáze, aby se načetli všichni relevantní zaměstnanci; Upozorňujeme, že to přenáší ke klientovi všechna data o zaměstnancích, i když bude potřeba jen plat.
  • Sledování změn EF Core vytváří snímky při načítání entit a pak tyto snímky porovnává s instancemi a zjistí, které vlastnosti se změnily.
  • Za účelem uložení všech změn se obvykle provádí druhý přístup k databázi (upozorňujeme, že někteří poskytovatelé databáze mohou změny rozdělit do více přístupů). I když je toto dávkové zpracování mnohem lepší než provádění jednoho dotazu pro každou aktualizaci, EF Core stále odesílá příkaz UPDATE pro každého zaměstnance a databáze musí každý příkaz spouštět samostatně.

Počínaje EF Core 7.0 můžete použít ExecuteUpdateAsync a ExecuteDeleteAsync metody, abyste to udělali mnohem efektivněji:

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

Tím se do databáze odešle následující příkaz SQL:

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

Tato UPDATE provádí celou operaci v jednom cyklu, aniž by načítala nebo odesílala jakákoli skutečná data do databáze, a bez použití mechanismu EF pro sledování změn, což znamená další zatížení. Další informace najdete v tématu ExecuteUpdate a ExecuteDelete.

Pokud používáte starší verzi EF Core, která ještě nepodporuje ExecuteUpdate a ExecuteDelete, nebo chcete spustit složitý příkaz SQL, který tyto metody nepodporuje, můžete k provedení operace použít dotaz SQL:

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

Další informace o rozdílech mezi SaveChanges a ExecuteUpdate/ExecuteDeletenajdete na stránce přehledu při ukládání dat.