0Pricing
C# Academy · Aula

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 Products

Dicas 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 ONLY

Contagem 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 1

Inserçõ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-trip

EF.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 simples
  • EF.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; use AnyAsync para 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

  1. Carregamento imediato, tardio e explícito
  2. SQL bruto, procedimentos armazenados e interpolação
  3. Consultas compiladas e desempenho
  4. Filtros globais de consulta e entidades próprias
← Voltar para C# Academy