Consultas compiladas e desempenho
Aumente o desempenho das consultas usando EF.CompileQuery, AsNoTracking e projeções com Select.
Consultas compiladas e desempenho é uma aula grátis de C# Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C# Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C# Academy inclui 4 aulas no total.
Compilação de consultas do EF Core
Sempre que o EF Core executa uma consulta LINQ, ele precisa analisar a árvore de expressões, traduzi-la para SQL e validá-la. Em caminhos críticos, essa sobrecarga se acumula. O EF Core oferece várias ferramentas para minimizá-la.
AsNoTracking para consultas somente leitura
AsNoTracking() ignora o registro no rastreador de alterações. Para consultas somente leitura (respostas de API e relatórios), esse é o maior ganho simples — normalmente, elas ficam de 2 a 5 vezes mais rápidas e consomem menos memória.
// With tracking (default) — for entities you'll modify
var tracked = await _db.Products.FirstOrDefaultAsync(p => p.Id == 1);
// Without tracking — for read-only
var dto = await _db.Products
.AsNoTracking()
.Where(p => p.IsActive)
.Select(p => new ProductDto { Id = p.Id, Name = p.Name })
.ToListAsync();Consultas compiladas
EF.CompileAsyncQuery pré-compila uma consulta LINQ em um delegado. A tradução acontece uma vez na inicialização; as chamadas subsequentes ignoram completamente a etapa de compilação.
// Define once, reuse many times
private static readonly Func<AppDbContext, int, Task<Product?>> GetProductById =
EF.CompileAsyncQuery(
(AppDbContext db, int id) =>
db.Products.AsNoTracking().FirstOrDefault(p => p.Id == id));
// Usage
var product = await GetProductById(_db, 42);Projeção com Select para obter desempenho
Sempre faça uma projeção contendo exatamente os campos necessários. Selecionar um DTO em vez de uma entidade completa reduz as colunas buscadas, a quantidade de dados transferidos pela rede e a pressão sobre o GC.
// Load entire entity (over-fetch)
var all = await _db.Products.ToListAsync();
// Projection: only fetch needed columns
var names = await _db.Products
.AsNoTracking()
.Select(p => new { p.Id, p.Name, p.Price })
.ToListAsync();
// SQL: SELECT Id, Name, Price FROM ProductsDicas de índice e otimização de consultas brutas
O EF Core respeita os índices do banco de dados que você configura com HasIndex(). Índices compostos, índices filtrados e colunas incluídas afetam o desempenho do plano de consulta.
// Configure compound index in OnModelCreating
modelBuilder.Entity<Order>()
.HasIndex(o => new { o.CustomerId, o.Status })
.HasFilter("[Status] = 0") // filtered index
.IncludeProperties(o => o.PlacedAt);
// The query below will use this index efficiently
var pending = await _db.Orders
.AsNoTracking()
.Where(o => o.CustomerId == 5 && o.Status == OrderStatus.Pending)
.ToListAsync();Paginação com Skip e Take
Sempre faça a paginação de grandes conjuntos de resultados. Skip e Take são traduzidos para OFFSET/FETCH no SQL, evitando carregar milhares de linhas na memória.
int page = 2, pageSize = 25;
var products = await _db.Products
.AsNoTracking()
.Where(p => p.IsActive)
.OrderBy(p => p.Name)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
// SQL: ... ORDER BY Name OFFSET 25 ROWS FETCH NEXT 25 ROWS ONLYContagem eficiente
Use CountAsync() ou AnyAsync() em vez de carregar registros apenas para contá-los. AnyAsync() é ainda mais rápido que COUNT quando você só precisa verificar a existência.
// Total count for pagination
int totalCount = await _db.Products
.Where(p => p.IsActive)
.CountAsync();
// Existence check — faster than Count > 0
bool hasExpensive = await _db.Products
.AnyAsync(p => p.Price > 1000m);
// SQL: IF EXISTS (SELECT 1 FROM ...) SELECT 1Inserções em massa com AddRange
Use AddRange para adicionar várias entidades de uma só vez. O EF Core agrupa as operações INSERT em menos viagens de ida e volta, controladas por MaxBatchSize no provedor.
var newProducts = Enumerable.Range(1, 1000)
.Select(i => new Product { Name = $"Product {i}", Price = i * 1.5m })
.ToList();
_db.Products.AddRange(newProducts);
await _db.SaveChangesAsync();
// Batched: typically 100-1000 rows per round-tripEF.Functions para funções do banco de dados
EF.Functions expõe funções específicas do banco de dados (LIKE, partes de datas e pesquisa de texto completo) que o EF Core traduz para SQL, em vez de avaliá-las na memória.
// LIKE pattern search (SQL-side)
var results = await _db.Products
.Where(p => EF.Functions.Like(p.Name, "%keyboard%"))
.AsNoTracking()
.ToListAsync();
// Date difference (SQL-side)
var recentOrders = await _db.Orders
.Where(o => EF.Functions.DateDiffDay(o.PlacedAt, DateTime.UtcNow) <= 7)
.ToListAsync();Diagnosticando consultas lentas
Ative o registro de consultas do EF Core para ver o SQL gerado. Use EnableSensitiveDataLogging() durante o desenvolvimento para ver os valores dos parâmetros.
builder.Services.AddDbContext<AppDbContext>(opt =>
opt.UseSqlServer(connStr)
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging() // dev only!
.EnableDetailedErrors()); // dev only!Na prática: ponto de acesso de listagem otimizado
Um ponto de acesso de listagem pronto para produção combina AsNoTracking, projeção, índices e paginação para obter o máximo desempenho.
app.MapGet("/products", async (
AppDbContext db,
string? search,
int page = 1, int size = 20) =>
{
var query = db.Products
.AsNoTracking()
.Where(p => p.IsActive);
if (!string.IsNullOrEmpty(search))
query = query.Where(p => EF.Functions.Like(p.Name, $"%{search}%"));
var total = await query.CountAsync();
var items = await query
.OrderBy(p => p.Name)
.Skip((page - 1) * size).Take(size)
.Select(p => new { p.Id, p.Name, p.Price })
.ToListAsync();
return Results.Ok(new { total, items });
});Verificação rápida
Qual é o principal benefício de EF.CompileAsyncQuery em comparação com uma consulta LINQ comum?
Recapitulação: consultas compiladas e desempenho
Principais conclusões:
AsNoTracking(): ignora o rastreador de alterações em consultas somente leitura — o maior ganho simplesEF.CompileAsyncQuery: pré-compila consultas críticas em delegados- Projeção com
Select: busca apenas as colunas necessárias - Índices adequados (
HasIndex) melhoram significativamente os planos de consulta - Faça paginação com
Skip/Take; useAnyAsyncpara verificar a existência - Ative o registro de consultas durante o desenvolvimento para detectar SQL lento ou inesperado
Perguntas Frequentes
A aula “Consultas compiladas e desempenho” é grátis?
Sim — o texto completo de “Consultas compiladas e desempenho” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C# Academy, atualize para CoddyKit PRO. O curso de C# Academy inclui 4 aulas no total.
O que vou aprender em “Consultas compiladas e desempenho”?
Aumente o desempenho das consultas usando EF.CompileQuery, AsNoTracking e projeções com Select. Você pratica C# Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar C# Academy?
Nenhuma experiência prévia é necessária. C# Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.
Quanto tempo leva a aula “Consultas compiladas e desempenho”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de C# Academy?
Sim. Cada aula de C# Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Carregamento imediato, tardio e explícito
- SQL bruto, procedimentos armazenados e interpolação
- Consultas compiladas e desempenho
- Filtros globais de consulta e entidades próprias