Kompilerade frågor och prestanda
Förbättra frågeprestandan med EF.CompileQuery, AsNoTracking och projektion med Select.
Kompilerade frågor och prestanda är en gratis lektion i C# Academy på CoddyKit. Detta är lektion 3 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för C# Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i C# Academy innehåller totalt 4 lektioner.
Kompilering av EF Core-frågor
Varje gång EF Core kör en LINQ-fråga måste det tolka uttrycksträdet, översätta det till SQL och validera det. För kodvägar som körs ofta blir den här överkostnaden betydande. EF Core erbjuder flera verktyg för att minimera den.
AsNoTracking för skrivskyddade frågor
AsNoTracking() hoppar över registreringen i ändringsspåraren. För skrivskyddade frågor (API-svar, rapporter) är detta den största enkla prestandavinsten – vanligtvis 2–5 gånger snabbare och med mindre minnesanvändning.
// 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();Kompilerade frågor
EF.CompileAsyncQuery förkompilerar en LINQ-fråga till en delegat. Översättningen sker en gång vid programstart; efterföljande anrop hoppar helt över kompileringssteget.
// 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);Projektion med Select för bättre prestanda
Projicera alltid till exakt de fält du behöver. Om du väljer en DTO i stället för en fullständig entitet minskar antalet hämtade kolumner, nätverksmängden och belastningen på 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 ProductsIndexhintar och optimering av råa frågor
EF Core respekterar databasindex som du konfigurerar med HasIndex(). Sammansatta index, filtrerade index och inkluderade kolumner påverkar alla frågeplanens prestanda.
// 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();Paginering med Skip och Take
Paginerar alltid stora resultatmängder. Skip och Take översätts till SQL:s OFFSET/FETCH, vilket undviker att tusentals rader läses in i minnet.
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 ONLYRäkna effektivt
Använd CountAsync() eller AnyAsync() i stället för att läsa in poster bara för att räkna dem. AnyAsync() är ännu snabbare än COUNT när du bara behöver kontrollera om något finns.
// 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 1Massinfogningar med AddRange
Använd AddRange för att lägga till flera entiteter på en gång. EF Core grupperar INSERT-satserna i färre turer, vilket styrs av MaxBatchSize i providern.
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 för databasfunktioner
EF.Functions tillhandahåller databasspecifika funktioner (LIKE, datumdelar, fulltextsökning) som EF Core översätter till SQL i stället för att utvärdera i minnet.
// 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();Diagnostisera långsamma frågor
Aktivera loggning av EF Core-frågor för att se den genererade SQL-koden. Använd EnableSensitiveDataLogging() under utveckling för att se parametervärden.
builder.Services.AddDbContext<AppDbContext>(opt =>
opt.UseSqlServer(connStr)
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging() // dev only!
.EnableDetailedErrors()); // dev only!Optimerad list-endpoint i praktiken
En produktionsklar list-endpoint kombinerar AsNoTracking, projektion, index och paginering för maximal prestanda.
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 });
});Snabbkontroll
Vilken är den främsta fördelen med EF.CompileAsyncQuery jämfört med en vanlig LINQ-fråga?
Sammanfattning: kompilerade frågor och prestanda
Viktiga punkter:
AsNoTracking(): hoppa över ändringsspåraren för skrivskyddade frågor – den enklaste stora prestandavinstenEF.CompileAsyncQuery: förkompilera frekventa frågor till delegater- Projektion med
Select: hämta endast nödvändiga kolumner - Korrekta index (
HasIndex) förbättrar frågeplanerna avsevärt - Paginerar med
Skip/Take; användAnyAsyncför att kontrollera om något finns - Aktivera frågeloggning under utveckling för att upptäcka långsam eller oväntad SQL
Lär dig C# med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 93
- Lektioner
- 346
Vanliga frågor
Är lektionen ”Kompilerade frågor och prestanda” gratis?
Ja – hela texten till ”Kompilerade frågor och prestanda” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i C# Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i C# Academy innehåller totalt 4 lektioner.
Vad lär jag mig i ”Kompilerade frågor och prestanda”?
Förbättra frågeprestandan med EF.CompileQuery, AsNoTracking och projektion med Select. Ni övar på C# Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig C# Academy?
Du behöver inga förkunskaper. Utbildningen i C# Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 3 av 4.
Hur lång tid tar lektionen ”Kompilerade frågor och prestanda”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här C# Academy-lektionen?
Ja. Varje C# Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Eager, lazy och explicit inläsning
- Rå SQL, lagrade procedurer och interpolering
- Kompilerade frågor och prestanda
- Globala frågefilter och ägda entiteter