7 Erros Fatais no EF Core: Dicas Para Otimizar Consultas

Imagine que você tenha construído uma aplicação inteirinha com Entity Framework Core🌍 Projeto: API de E-Commerce com ASP.NET Core e SQL Server!🌍 Projeto: API de E-Commerce com ASP.NET Core e SQL Server!Aprenda a construir uma API robusta para e-commerce com ASP.NET Core, EF Core, JWT e Swagger, validando suas habilidades em um projeto prático real. e, quando coloca em produção, percebe que as consultas estão lerdas, travando o sistema e deixando usuários irritados. Isso pode acontecer por vários motivos, mas existem 7 erros clássicos (e mortais!) que todo mundo comete pelo menos uma vez na vida. Vamos explorar cada um, entender o porquê deles acontecerem e, claro, como corrigir e otimizar seu código para ganhar performance.

Índice🔗

Pecado #1: Carregar o Universo com Include Exagerado🔗

O uso abusivo do Include é um clássico. Às vezes, você quer trazer dados relacionados, mas acaba incluindo tabelas e tabelas sem nem precisar. Isso gera uma consulta🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. enorme e um “carregamento do universo”.

Exemplo de como não fazer:

var pedidos = context.Pedidos
    .Include(p => p.Cliente)
    .Include(p => p.Cliente.Endereco)
    .Include(p => p.Itens)
    .ThenInclude(i => i.Produto)
    .Include(p => p.Status)
    .ToList();

Se você só vai exibir na tela o nome do cliente e a data do pedido, não faz sentido trazer endereço, itens e produto🔢 Operadores Aritméticos: Faça Cálculos como uma Calculadora Humana!🔢 Operadores Aritméticos: Faça Cálculos como uma Calculadora Humana!Aprenda a dominar operadores aritméticos em C# com exemplos práticos, técnicas de cálculo e dicas para evitar erros e maximizar resultados.. Cada Include extra representa mais carga ao banco e📊 Behavior-Driven Development: Testes que Todo Mundo Entende!📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. ao transporte de dados.

Como Resolver:

Pecado #2: Usar Lazy Loading sem Limites (N+1 Problem)🔗

O Lazy Loading pode ser conveniente, mas é traiçoeiro: se você tem uma lista de 100 itens, e para cada item você acessa uma propriedade⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!Aprenda como utilizar propriedades em C# para encapsular dados, validar informações e manter um código organizado, seguro e de fácil manutenção. de navegação, o EF Core pode disparar 100 consultas extras (uma para cada item!), culminando no famoso “N+1 Problem”.

Exemplo de código problemático:

var pedidos = context.Pedidos.ToList();
foreach (var pedido in pedidos)
{
    Console.WriteLine(pedido.Cliente.Nome);
    // Aqui pode ocorrer uma query para cada pedido, se Lazy Loading estiver habilitado
}

Como Resolver:

Pecado #3: Falta de Paginação e Filtros Claros🔗

Trazer milhares de registros de uma só vez pode explodir sua memória e demorar um tempão. Paginar resultados e filtrar🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. com precisão ajuda muito o banco e também a aplicação a lidar melhor com os dados.

Exemplo de paginaçãoConsultas Eficientes com Entity Framework para Grandes Bases de DadosConsultas Eficientes com Entity Framework para Grandes Bases de DadosSaiba como otimizar consultas com Entity Framework em grandes volumes de dados com técnicas de projeção, eager loading, e paginação para alta performance. simples:

int pagina = 1;
int tamanhoPagina = 10;
var clientesPaginados = context.Clientes
    .OrderBy(c => c.Nome)
    .Skip((pagina - 1) * tamanhoPagina)
    .Take(tamanhoPagina)
    .ToList();

Com paginação, você economiza recursos do banco e do transporte de dados, além de melhorar a experiência🌐 LinkedIn para Devs .NET: Perfil que Atrai Recrutadores!🌐 LinkedIn para Devs .NET: Perfil que Atrai Recrutadores!Aprenda a otimizar seu perfil LinkedIn com dicas essenciais para devs .NET. Conquiste oportunidades e destaque suas habilidades! do usuário.

Pecado #4: Não Usar AsNoTracking quando Necessário🔗

Para buscas meramente informativas (quando não há atualização de dados), o EF Core🌍 Projeto: API de E-Commerce com ASP.NET Core e SQL Server!🌍 Projeto: API de E-Commerce com ASP.NET Core e SQL Server!Aprenda a construir uma API robusta para e-commerce com ASP.NET Core, EF Core, JWT e Swagger, validando suas habilidades em um projeto prático real. não precisa manter o “tracking” de tudo em memória. Usar AsNoTracking() impede que cada objeto seja monitorado para alterações, melhorando bastante a performance🔄 StringBuilder: Quando Concatenar Strings Vira um Pesadelo!🔄 StringBuilder: Quando Concatenar Strings Vira um Pesadelo!Descubra como o StringBuilder otimiza a concatenação em C#, evitando desperdício de memória e melhorando a performance das aplicações. Veja exemplos práticos! em cenários de leitura pesada.

var produtos = context.Produtos
    .AsNoTracking()
    .Where(p => p.Ativo)
    .ToList();

Se a ideia é só exibir dados, não tem por que manter tracking das entidades.

Pecado #5: Ignorar a Seleção de Campos Específicos (Projeção)🔗

Muitas vezes, você só quer duas ou três colunas, mas busca a entidade inteira, com dezenas de propriedades⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!Aprenda como utilizar propriedades em C# para encapsular dados, validar informações e manter um código organizado, seguro e de fácil manutenção.. O EF Core tem suporte a projeção usando Select🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio., que evita trazer dados desnecessários.

var listaNomesPrecos = context.Produtos
    .Select(p => new { p.Nome, p.Preco })
    .AsNoTracking()
    .ToList();

Além de reduzir o volume de dados transferidos, isso pode aliviar o tempo de retorno do banco enormemente.

Pecado #6: Falta de Índices e Ajustes no Banco🔗

Mesmo com EF Core🌍 Projeto: API de E-Commerce com ASP.NET Core e SQL Server!🌍 Projeto: API de E-Commerce com ASP.NET Core e SQL Server!Aprenda a construir uma API robusta para e-commerce com ASP.NET Core, EF Core, JWT e Swagger, validando suas habilidades em um projeto prático real., seu banco ainda precisa de uma boa modelagem e índices adequados. Se você não tiver índices nas colunas que são frequentemente usadas em Where🔍 LINQ Básico: Filtre Dados como um Garimpeiro Digital!🔍 LINQ Básico: Filtre Dados como um Garimpeiro Digital!Descubra como o LINQ facilita o processamento de dados em C#. Filtre, ordene e transforme coleções com precisão e eficiência no seu código. ou Join, sua consulta🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. vai ser superlenta.

Dicas🔢 Operadores Aritméticos: Faça Cálculos como uma Calculadora Humana!🔢 Operadores Aritméticos: Faça Cálculos como uma Calculadora Humana!Aprenda a dominar operadores aritméticos em C# com exemplos práticos, técnicas de cálculo e dicas para evitar erros e maximizar resultados. para não pecar aqui:

Pecado #7: Consultas Síncronas Gigantes (Esquecendo o Async)🔗

Em aplicações modernas, usar operações assíncronasRepositório Assíncrono: Como Estruturar o Acesso a DadosRepositório Assíncrono: Como Estruturar o Acesso a DadosDescubra como implementar um repositório assíncrono em C# seguindo boas práticas de separação de responsabilidades e eficiência de dados. ajuda a liberar threads enquanto espera a resposta do banco. Se você chamar .ToList() para grandes consultas🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. e não usar .ToListAsync(), pode travar a threadDiferenças entre Threads, Tasks e Delegates em C#Diferenças entre Threads, Tasks e Delegates em C#Aprenda as diferenças entre Threads, Tasks e Delegates em C#. Este tutorial prático ensina como otimizar a execução paralela e melhorar o desempenho. de requisição inteira, resultando em lentidão geral.

var listaProdutos = await context.Produtos
    .Where(p => p.Estoque > 0)
    .ToListAsync();

Com isso, seu servidor lida melhor com múltiplas requisições ao mesmo tempo e📊 Behavior-Driven Development: Testes que Todo Mundo Entende!📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. evita gargalos desnecessários.

Tracking Desnecessário: O Assassino Silencioso🔗

O Crime:

var produtos = context.Produtos.ToList(); // Tracking automático!

O EF Core rastreia todas as entidades por padrão, consumindo memória e CPU mesmo em consultas🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. de apenas leitura.

A Redenção:

var produtos = context.Produtos
    .AsNoTracking()
    .ToList(); // Desliga o rastreamento

Impacto: Redução de até 40% no consumo de memória🔄 StringBuilder: Quando Concatenar Strings Vira um Pesadelo!🔄 StringBuilder: Quando Concatenar Strings Vira um Pesadelo!Descubra como o StringBuilder otimiza a concatenação em C#, evitando desperdício de memória e melhorando a performance das aplicações. Veja exemplos práticos! em consultas grandes (Fonte: Microsoft Benchmarks⏱️ Benchmark.NET: Meça a Velocidade do Seu Código!⏱️ Benchmark.NET: Meça a Velocidade do Seu Código!Aprenda a usar o Benchmark.NET para medir a performance de seu código com precisão. Descubra dicas, práticas confiáveis e evite erros comuns..

Select N+1: O Pesadelo das Queries Invisíveis🔗

O Crime:

var pedidos = context.Pedidos.ToList();
foreach (var pedido in pedidos)
{
    // Gera uma nova query para cada pedido!
    var cliente = context.Clientes.Find(pedido.ClienteId);
}

A Redenção:

var pedidos = context.Pedidos
    .Include(p => p.Cliente) // Carrega tudo de uma vez
    .ToList();

Dica: Use ThenInclude para🔄 Loops em C#: Repita Tarefas sem Enlouquecer (Com for e while!)🔄 Loops em C#: Repita Tarefas sem Enlouquecer (Com for e while!)Descubra como automatizar repetições em C# utilizando loops for e while com exemplos práticos que evitam erros e otimizam seu código. Aprenda mais! hierarquias complexas:

.Include(p => p.Itens)
    .ThenInclude(i => i.Produto)

Consultas em Loop: Quando o Laço Vira uma Corda🔗

O Crime:

foreach (var id in idsDeClientes)
{
    var cliente = context.Clientes.Find(id); // 1000 ids = 1000 queries!
}

A Redenção:

var clientes = context.Clientes
    .Where(c => idsDeClientes.Contains(c.Id))
    .ToList(); // 1 query para todos

Impacto: Consulta🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. com 1000 IDs: 100x mais rápido ⚡

Carregar Tudo: O Hambúrguer de 10 Andares🔗

O Crime:

var clientes = context.Clientes.ToList(); // SELECT * FROM Clientes

A Redenção:

var clientes = context.Clientes
    .Select(c => new
    {
        c.Id,
        c.Nome,
        c.Email
    }).ToList(); // SELECT apenas colunas necessárias

Bônus: Use DTOs para consultas🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. complexas:

public class ClienteResumoDto
{
    public int Id { get; set; }
    public string Nome { get; set; }
}
var clientes = context.Clientes
    .Select(c => new ClienteResumoDto { /* ... */ })
    .ToList();

Índices Fantasmas: A Ilusão da Performance🔗

Sintomas:

Solução Mágica:

CREATE INDEX IX_Clientes_Email ON Clientes (Email);

No EF Core🌍 Projeto: API de E-Commerce com ASP.NET Core e SQL Server!🌍 Projeto: API de E-Commerce com ASP.NET Core e SQL Server!Aprenda a construir uma API robusta para e-commerce com ASP.NET Core, EF Core, JWT e Swagger, validando suas habilidades em um projeto prático real.:

modelBuilder.Entity<Cliente>()
    .HasIndex(c => c.Email)
    .IsUnique();

Regra de Ouro: Índices em colunas usadas em filtros, ordenações🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. e joins.

Processamento em Memória: O Disfarce de Query🔗

O Crime:

var produtos = context.Produtos
    .ToList() // ⚠️ Traz TUDO para a memória!
    .Where(p => p.Preco > 1000);

A Redenção:

var produtos = context.Produtos
    .Where(p => p.Preco > 1000) // Filtro no SQL
    .ToList();

Comparação:

CenárioRegistros no BDTempo
ToList + Where1.000.00015s ⚠️
Where + ToList1.000.0002s ✅

Paginação Ingênua: O Falso Amigo🔗

O Crime:

var page1 = context.Produtos.Skip(0).Take(10).ToList();
var page2 = context.Produtos.Skip(10).Take(10).ToList();
// ...

Problema🤝 GitHub Básico: Versionamento para Iniciantes!🤝 GitHub Básico: Versionamento para Iniciantes!Descubra como o GitHub facilita colaboração, versionamento e organização de código com este tutorial prático e essencial para desenvolvedores iniciantes.: SkipMaximizando Performance com Operadores Diferenciados (Skip, Take, AsParallel)Maximizando Performance com Operadores Diferenciados (Skip, Take, AsParallel)Descubra como otimizar suas consultas LINQ com os poderosos operadores Skip, Take e AsParallel, melhorando performance e eficiência no tratamento de dados. fica mais lento conforme a página aumenta.

Solução Profissional:

var ultimoId = page1.Last().Id;
var page2 = context.Produtos
    .Where(p => p.Id > ultimoId)
    .Take(10)
    .ToList();

Vantagem: Tempo constante ⏱️ independente da página!

Bônus: Diagnóstico de Performance

1. Log de Consultas🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio.:

optionsBuilder.UseSqlServer(connectionString)
    .LogTo(Console.WriteLine, LogLevel.Information);

2. Analise o Plano de Execução:

EXEC sp_executesql N'SELECT * FROM Clientes WHERE Id = @p0', N'@p0 int', 123
-- Clique em "Execution Plan" no SSMS

3. EF Core🌍 Projeto: API de E-Commerce com ASP.NET Core e SQL Server!🌍 Projeto: API de E-Commerce com ASP.NET Core e SQL Server!Aprenda a construir uma API robusta para e-commerce com ASP.NET Core, EF Core, JWT e Swagger, validando suas habilidades em um projeto prático real. Insights:

services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(connectionString)
        .EnableSensitiveDataLogging()
        .EnableDetailedErrors());

Lembre-se: Monitorar é tão importante quanto otimizar! 🕵️♂️

No final das contas, a performance do EF Core não é uma questão mágica, mas uma soma de boas práticas🔢 Operadores Aritméticos: Faça Cálculos como uma Calculadora Humana!🔢 Operadores Aritméticos: Faça Cálculos como uma Calculadora Humana!Aprenda a dominar operadores aritméticos em C# com exemplos práticos, técnicas de cálculo e dicas para evitar erros e maximizar resultados. de código, design de banco e monitoramento constante. Evitar esses 7 pecados já vai te colocar em um patamar bem mais tranquilo e performático!

Autor: Marcelo V. Souza - Engenheiro de Sistemas e Entusiasta em IoT e Desenvolvimento de Software, com foco em inovação tecnológica.

Referências🔗

Compartilhar artigo

Artigos Relacionados