Atualização Eficiente

Envio em lote

O EF Core ajuda a minimizar as idas e voltas agrupando automaticamente todas as atualizações em uma única ida e volta. Considere estes fatores:

var blog = context.Blogs.Single(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" });
context.SaveChanges();

O anterior carrega um blog a partir 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 por uma, à medida que instâncias de blob são adicionadas, o EF Core controla essas alterações internamente e as executa em uma única ida e volta quando SaveChanges é chamado.

O número de instruções que o EF envia 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 lotes 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 são degradados após 40 instruções para o SQL Server, portanto, o EF Core executará por padrão apenas 42 instruções em um único lote e executará instruções adicionais em idas e voltas separadas.

Os usuários também pode ajustar esses limites para obter um desempenho potencialmente maior, mas use os parâmetros de comparação 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));
}

Use 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 seria da seguinte maneira:

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

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 ida e volta de banco de dados é executada para salvar (observe que alguns provedores de banco de dados dividem as alterações em várias idas e voltas). Embora esse comportamento de envio em lote seja muito melhor do que uma 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ções separadamente.

A partir do EF Core 7.0, você pode usar os métodos ExecuteUpdate e ExecuteDelete para fazer a mesma coisa com muito mais eficiência:

context.Employees.ExecuteUpdate(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 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.