Requêtes compilées et performances
Améliorez les performances des requêtes avec EF.CompileQuery, AsNoTracking et la projection avec Select.
Requêtes compilées et performances est une leçon C# Academy gratuite sur CoddyKit. Ceci est la leçon 3 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage C# Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours C# Academy comprend 4 leçons au total.
Compilation des requêtes EF Core
Chaque fois qu'EF Core exécute une requête LINQ, il doit analyser l'arbre d'expressions, le traduire en SQL et le valider. Pour les chemins très sollicités, ce surcoût s'accumule. EF Core fournit plusieurs outils pour le réduire.
AsNoTracking pour les requêtes en lecture seule
AsNoTracking() ignore l'enregistrement dans le système de suivi des modifications. Pour les requêtes en lecture seule (réponses d'API, rapports), c'est le gain facile le plus important — généralement 2 à 5 fois plus rapide et avec une consommation mémoire réduite.
// 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();Requêtes compilées
EF.CompileAsyncQuery précompile une requête LINQ en délégué. La traduction n'a lieu qu'une seule fois au démarrage ; les appels suivants ignorent entièrement l'étape de compilation.
// 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);Projection avec Select pour de meilleures performances
Projetez toujours les données vers les champs dont vous avez exactement besoin. Sélectionner un DTO plutôt qu'une entité complète réduit le nombre de colonnes récupérées, la charge utile du réseau et la pression exercée sur le ramasse-miettes.
// 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 ProductsIndications d'index et optimisation des requêtes brutes
EF Core respecte les index de base de données que vous configurez avec HasIndex(). Les index composites, les index filtrés et les colonnes incluses influencent tous les performances du plan d'exécution.
// 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();Pagination avec Skip et Take
Utilisez toujours la pagination pour les grands ensembles de résultats. Skip et Take sont traduits en OFFSET/FETCH SQL, ce qui évite de charger des milliers de lignes en mémoire.
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 ONLYCompter efficacement
Utilisez CountAsync() ou AnyAsync() plutôt que de charger des enregistrements uniquement pour les compter. AnyAsync() est même plus rapide que COUNT lorsqu'il vous suffit de vérifier l'existence d'un élément.
// 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 1Insertions groupées avec AddRange
Utilisez AddRange pour ajouter plusieurs entités en une seule fois. EF Core regroupe les INSERT en moins d'allers-retours, selon la valeur de MaxBatchSize définie par le fournisseur.
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 pour les fonctions de base de données
EF.Functions expose des fonctions propres aux bases de données (LIKE, parties de date, recherche en texte intégral) qu'EF Core traduit en SQL au lieu de les évaluer en mémoire.
// 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();Diagnostiquer les requêtes lentes
Activez la journalisation des requêtes EF Core pour voir le SQL généré. Utilisez EnableSensitiveDataLogging() en développement pour afficher les valeurs des paramètres.
builder.Services.AddDbContext<AppDbContext>(opt =>
opt.UseSqlServer(connStr)
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging() // dev only!
.EnableDetailedErrors()); // dev only!Cas concret : point de terminaison de liste optimisé
Un point de terminaison de liste prêt pour la production combine AsNoTracking, la projection, les index et la pagination pour des performances maximales.
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 });
});Vérification rapide
Quel est le principal avantage de EF.CompileAsyncQuery par rapport à une requête LINQ classique ?
Récapitulatif : requêtes compilées et performances
Points essentiels :
AsNoTracking(): ignore le suivi des modifications pour la lecture seule — le gain facile le plus rapideEF.CompileAsyncQuery: précompile les requêtes très sollicitées en délégués- Projection avec
Select: récupère uniquement les colonnes nécessaires - Des index appropriés (
HasIndex) améliorent considérablement les plans d'exécution - Utilisez la pagination avec
Skip/Take; utilisezAnyAsyncpour vérifier l'existence - Activez la journalisation des requêtes en développement pour détecter les requêtes SQL lentes ou inattendues
Questions Fréquemment Posées
La leçon « Requêtes compilées et performances » est-elle gratuite ?
Oui — le texte complet de « Requêtes compilées et performances » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours C# Academy, passe à CoddyKit PRO. Le cours C# Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Requêtes compilées et performances » ?
Améliorez les performances des requêtes avec EF.CompileQuery, AsNoTracking et la projection avec Select. Tu pratiques C# Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer C# Academy ?
Aucune expérience préalable n'est requise. C# Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 3 sur 4.
Combien de temps prend la leçon « Requêtes compilées et performances » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon C# Academy ?
Oui. Chaque leçon C# Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Chargement immédiat, différé et explicite
- SQL brut, procédures stockées et interpolation
- Requêtes compilées et performances
- Filtres de requêtes globaux et entités possédées