Performance no EFCore | C#
- Performance no EFCore | C#
🚀 Como melhorar performance no EF Core 8
1. Use AsNoTracking() sempre que possível
Para consultas somente leitura, utilize AsNoTracking() para desativar o change tracking — reduzindo uso de CPU e memória:
var authors = await context.Authors
.AsNoTracking()
.Where(a => a.IsActive)
.ToListAsync();
Isso evita o overhead de rastrear entidades que não serão modificadas ([LinkedIn][1], [LinkedIn][2]).
2. Use consultas compiladas (Compiled Queries)
Consultas LINQ são compiladas em SQL, e podem gerar overhead se forem executadas muitas vezes. Consultas compiladas evitam recompilação, acelerando cenários de alta frequência:
static readonly Func<MyDbContext,int,IAsyncEnumerable<Blog>>
_compiledBlogs = EF.CompileAsyncQuery(
(MyDbContext ctx, int minPosts) =>
ctx.Blogs.Where(b => b.PostCount > minPosts));
await foreach (var blog in _compiledBlogs(context, 10))
{
Console.WriteLine(blog.Title);
}
Esse tipo de query pode reduzir tempo de execução de ~670 μs para ~560 μs em benchmarks ([LinkedIn][1]).
3. Indexação adequada no banco
Crie índices nos campos mais usados em filtros, ordenações e junções. Você pode configurar direto no modelo EF:
modelBuilder.Entity<Order>()
.HasIndex(o => o.CustomerId);
Índices diminuem drasticamente os tempos de busca no banco.
4. Paginação e projeções (Select)
Evite carregar grandes volumes de dados em memória: use Select() para trazer apenas campos necessários e Skip()/Take() para paginação:
var page = await context.Orders
.Where(o => o.Status == status)
.Select(o => new { o.Id, o.Total, o.Date })
.Skip((pageNum - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
Isso reduz consumo de rede, memória e tempo de resposta.
5. Eager vs Lazy Loading e Detectando explosão cartesiana
- Prefira eager loading quando for carregar entidades relacionadas para evitar múltiplas consultas (N+1).
- Use explicit loading ou
Include().AsSplitQuery()em cenários complexos, evitando explosões de duplicação de dados:
var books = context.Authors
.Include(a => a.Books)
.AsSplitQuery()
.ToList();
Isso evita duplicações e melhora desempenho em relacionamentos 1:N.

🎯 Novidades do EF Core 8 que ajudam na performance
✅ Complex Types
EF Core 8 agora suporta Complex Types, que permitem mapear objetos compostos sem gerar uma tabela separada. Isso simplifica o modelo e melhora performance em inserções e consultas:
public class Customer {
public int Id { get; set; }
public Address Address { get; set; }
}
public class Address {
public string City { get; set; }
public string Country { get; set; }
}
No banco, os campos de Address virão na mesma tabela do Customer ([Dan Does Code][4]).
✅ Bulk Updates & Deletes aprimorados
Use ExecuteUpdate() e ExecuteDelete() para realizar operações em lote no banco sem carregar entidades em memória:
await context.Orders
.Where(o => o.Status == Status.Pending)
.ExecuteUpdateAsync(b => b.SetProperty(o => o.Status, Status.Processed));
Reduz round-trips e melhora eficiência em operações de grande escala ([InfoWorld][5], [LinkedIn][2]).
🧪 Outras boas práticas adicionais para EF Core 8
-
Use
DbContextPoolpara reduzir overhead de criação de contextoservices.AddDbContextPool<MyDbContext>(opt => opt.UseSqlServer(conn));Isso reutiliza objetos e economiza memória e CPU ([Microsoft Learn][6]).
-
Desative
AutoDetectChangesEnableddurante bulk operationscontext.ChangeTracker.AutoDetectChangesEnabled = false;
context.UpdateRange(entities);
await context.SaveChangesAsync();
context.ChangeTracker.AutoDetectChangesEnabled = true;Remove detecção automática de mudanças, acelerando operações em massa ([LinkedIn][2]).
-
Evite criar queries com Expression API incorreta Evite usar Expression com valores constantes que causem recompilação da consulta; prefira parâmetros simples:
var title = "post1";
var post = await context.Posts.FirstOrDefaultAsync(p => p.Title == title);Isso permite reutilização do cache de query.
-
Use async em vez de sincrono
await context.Entities.ToListAsync();
await context.SaveChangesAsync();Melhora escalabilidade e responsividade da aplicação ([InfoWorld][5], [LinkedIn][1]).
-
Monitore consultas e gargalos Use logging do EF Core e ferramentas como Application Insights para identificar consultas lentas e otimizar o plano de execução do banco de dados ([LinkedIn][1]).
📚 Exemplos consolidados: Comparativo
| Recurso | Praktica recomendada | Benefício |
|---|---|---|
AsNoTracking | context.Entities.AsNoTracking() | Menor uso de memória e CPU em leitura |
| Consultas compiladas | EF.CompileAsyncQuery() | Evita recompilação LINQ |
| Indexação | HasIndex() no modelo | Busca mais rápida no BD |
| Paginação & projeções | .Skip().Take() + Select() | Menor payload transferido |
| Loading eficiente | Include()/AsSplitQuery() | Evita múltiplos queries e duplicação |
| Bulk updates | ExecuteUpdate() / ExecuteDelete() | Eficiência sem carregar entidades |
| Pool de DbContext | AddDbContextPool() | Reúso de instâncias e menos GC overhead |
| Desativar detecção automática | AutoDetectChangesEnabled = false | Melhor performance em lotes |
| Async | ToListAsync(), SaveChangesAsync() | Melhor escalabilidade e performance I/O |
| Monitoramento | Logs e APM (por ex. App Insights) | Facilita diagnóstico e otimização contínua |