EF Core - Inserindo registros em massa (BulkInsert)   


 Neste artigo veremos como incluir registros em massa usando o EF Core.


Quando você precisar inserir centenas, milhares ou milhões de entidades usando o método SaveChanges() do EF Core, você notará que o desempenho do seu aplicativo vai ficar muito lento.

 

Isso ocorre porque o método SaveChanges() requer uma viagem de ida e volta do banco de dados para cada entidade a ser inserida. Portanto, se você precisar inserir 10.000 entidades, serão realizadas 10.000 viagens de ida e volta ao banco de dados e seu aplicativo sofrerá com problemas de desempenho.

 

O método AddRange melhorou um pouco o desempenho mas o gargalho esta mesmo no método SaveChanges().

 

Uma alternativa para contornar esse problema e melhorar o desempenho da inclusão de registros em massa é usar a biblioteca Z.EntityFramework.Extensions.EFCore que oferece dentre outros recursos o método de extensão BulkInsert que requer o mínimo de viagens de ida e volta do banco de dados em comparação com SaveChanges().

 

A seguir temos uma comparação dos tempos gastos usando o recurso BulkInsert() com o SaveChanges():
 

 

Percebe-se que o BulkInsert é muito mais rápido.
 

Para usar este recurso basta instalar o no seu projeto o pacote Nuget:  Z.EntityFramework.Extensions.EFCore

Install-Package Z.EntityFramework.Extensions.EFCore -Version 5.1.36

Ou usando o menu Tools no Visual Studio 2019 :



 

Para mostrar o recurso eu vou usar um projeto Console onde já temos definidos o EF Core 5.0 e o mapeamento realizado usando a Fluent API para as entidades : Pedido, Item, Cliente e Produto.


Nota:  Para detalhes da criação do projeto e do mapeamento usando a Fluent API veja o seguinte artigo : EF Core - Sistema de Vendas : Usando a Fluent API

 

Assim o nosso modelo de entidades possui as seguintes definições e associações :
 


Incluindo registros em massa com BulkInsert

Vamos então fazer um teste e confirmar se o desempenho do BulkInsert é realmente mais rápido.

A título de exemplo vamos incluir 4 produtos na tabela Produtos usando o BulkInsert e comparando o resultado com a utilização de AddRange e SaveChanges.

Assim no método Main da classe Program inclua o código a seguir:

using System;
using System.Collections.Generic;
using Vendas.Context;
using Vendas.Entities;
namespace Vendas
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            using (var ctx = new ApplicationDbContext())    
            {
                var listaProdutos = GetProdutos();
                var watch1 = System.Diagnostics.Stopwatch.StartNew();

                ctx.AddRange(listaProdutos);
                ctx.SaveChanges();
                watch1.Stop();
                var elapsedMs1 = watch1.ElapsedMilliseconds;
                Console.WriteLine($"\nSaveChanges : {elapsedMs1}\n");
                var watch2 = System.Diagnostics.Stopwatch.StartNew();

                ctx.BulkInsert(listaProdutos);               
                watch2.Stop();
                var elapsedMs2 = watch2.ElapsedMilliseconds;
                Console.WriteLine($"\nBulkInsert : {elapsedMs2}");
            }
            Console.ReadKey();
        }
        static private List<Produto> GetProdutos()
        {
            var produtos = new List<Produto>
            {
               new Produto{ Nome="Borracha",Descricao="Borracha branca",Preco = 4.55M,Ativo= true},
               new Produto{ Nome="Estojo",Descricao="Estojo pequeno",Preco = 6.25M,Ativo= true},
               new Produto{ Nome="Transferidor",Descricao="Transferidor",Preco = 9.65M,Ativo= true},
               new Produto{ Nome="Clips",Descricao="Clips pequeno",Preco = 2.85M,Ativo= true}
            };
            return produtos;
        }
    }
}

Embora o número de registros seja bem pequeno já podemos ter uma ideia do desempenho. Executando o projeto acima iremos obter o seguinte resultado:

Nada mal, o BulkInsert mostrou ser quase 4 vezes mais rápido...

Assim, creio que vale a pena dar uma olhada nesta biblioteca com mais detalhes.

Obs : Se a quantidade de registros for colossal, nada como você mesmo criar a sua instrução SQL, e assim com certeza você obterá um desempenho melhor.

"Não estejais inquietos por coisa alguma; antes as vossas petições sejam em tudo conhecidas diante de Deus pela oração e súplica, com ação de graças."
Filipenses 4:6

Referências:


José Carlos Macoratti