Atualização eficiente
Separação em lotes
O EF Core ajuda a minimizar as viagens de ida e volta agrupando automaticamente todas as atualizações em uma única viagem de ida e volta. Considere o seguinte:
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();
O acima carrega um blog do banco de dados, altera sua URL e adiciona dois novos blogs; para aplicar isso, duas instruções SQL INSERT e uma instrução UPDATE são enviadas para o banco de dados. Em vez de enviá-las uma a uma, à medida que as instâncias de Blog são adicionadas, o EF Core rastreia essas alterações internamente e as executa em uma única operação quando o método SaveChanges é chamado.
O número de instruções que o EF envia em lotes em uma única ida e volta depende do provedor de banco de dados que está sendo usado. Por exemplo, a análise de desempenho mostrou que o envio em lote geralmente é menos eficiente para o SQL Server quando menos de 4 instruções estão envolvidas. Da mesma forma, os benefícios do envio em lote se degradam após cerca de 40 instruções para SQL Server. Portanto, o EF Core executará por padrão apenas até 42 instruções em um único lote e enviará instruções adicionais em rodadas separadas.
Os usuários também podem ajustar esses limites para obter um desempenho potencialmente maior , mas fazer benchmark cuidadosamente antes de modificá-los:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(
@"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True",
o => o
.MinBatchSize(1)
.MaxBatchSize(100));
}
Usar ExecuteUpdate e ExecuteDelete quando relevante
Vamos supor que você queira dar um aumento a todos os seus funcionários. Uma implementação típica para isso no EF Core teria a seguinte aparência:
foreach (var employee in context.Employees)
{
employee.Salary += 1000;
}
await context.SaveChangesAsync();
Embora este seja um código perfeitamente válido, vamos analisar o que ele faz de uma perspectiva de desempenho:
- Uma ida e volta de banco de dados é executada para carregar todos os funcionários relevantes; observe que isso traz todos os dados de linha dos funcionários para o cliente, mesmo que apenas o salário seja necessário.
- O controle de alterações do EF Core cria instantâneos ao carregar as entidades e compara esses instantâneos com as instâncias para descobrir quais propriedades foram alteradas.
- Normalmente, uma segunda consulta ao banco de dados é realizada para salvar todas as alterações (observe que alguns provedores de banco de dados dividem as alterações em múltiplas consultas). Embora esse comportamento de envio em lote seja muito melhor do que fazer uma viagem de ida e volta para cada atualização, o EF Core ainda envia uma instrução UPDATE por funcionário e o banco de dados deve executar cada instrução separadamente.
A partir do EF Core 7.0, você pode usar os métodos ExecuteUpdateAsync
e ExecuteDeleteAsync
para fazer a mesma coisa com muito mais eficiência:
await context.Employees.ExecuteUpdateAsync(s => s.SetProperty(e => e.Salary, e => e.Salary + 1000));
Isso envia a seguinte instrução SQL para o banco de dados:
UPDATE [Employees] SET [Salary] = [Salary] + 1000;
Esse UPDATE
executa toda a operação em uma única viagem de ida e volta, sem carregar ou enviar dados reais para o banco de dados e sem usar o computador de controle de alterações do EF, o que impõe uma sobrecarga adicional. Para obter mais informações, consulte ExecuteUpdate
e ExecuteDelete
.
Se você estiver usando uma versão mais antiga do EF Core que ainda não dá suporte a ExecuteUpdate
e ExecuteDelete
ou deseja executar uma instrução SQL complexa que não é compatível com esses métodos, você ainda pode usar uma consulta SQL para executar a operação:
context.Database.ExecuteSql($"UPDATE [Employees] SET [Salary] = [Salary] + 1000");
Para saber mais sobre as diferenças entre SaveChanges
e ExecuteUpdate
/ExecuteDelete
, consulte a página visão geral sobre como salvar dados.