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: