Kompilerede forespørgsler og ydeevne
Forbedr forespørgslers ydeevne med EF.CompileQuery, AsNoTracking og projektion med Select.
Kompilerede forespørgsler og ydeevne er en gratis C# Academy-lektion på CoddyKit. Dette er lektion 3 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i C# Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. C# Academy-kurset indeholder 4 lektioner i alt.
Kompilering af EF Core-forespørgsler
Hver gang EF Core udfører en LINQ-forespørgsel, skal den analysere udtrykstræet, oversætte det til SQL og validere det. For ofte kørte kodeveje løber denne ekstraomkostning op. EF Core tilbyder flere værktøjer til at minimere den.
AsNoTracking til skrivebeskyttede forespørgsler
AsNoTracking() springer registreringen i ændringssporingen over. For skrivebeskyttede forespørgsler (API-svar, rapporter) er dette den største nemme gevinst – typisk 2–5 gange hurtigere og med mindre hukommelsesforbrug.
// 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();Kompilerede forespørgsler
EF.CompileAsyncQuery forkompilerer en LINQ-forespørgsel til en delegat. Oversættelsen sker én gang ved opstart, og efterfølgende kald springer kompileringstrinnet helt over.
// 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 for bedre ydeevne
Projicér altid til præcis de felter, du har brug for. Ved at vælge en DTO i stedet for en komplet entitet reducerer du antallet af hentede kolonner, netværksmængden og GC-belastningen.
// 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 ProductsIndekstips og optimering af rå forespørgsler
EF Core respekterer de databaseindekser, du konfigurerer med HasIndex(). Sammensatte indekser, filtrerede indekser og inkluderede kolonner påvirker alle forespørgselsplanens ydeevne.
// 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();Sideinddeling med Skip og Take
Sideinddel altid store resultatsæt. Skip og Take oversættes til SQL OFFSET/FETCH, så du undgår at indlæse tusindvis af rækker i hukommelsen.
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 ONLYEffektiv optælling
Brug CountAsync() eller AnyAsync() i stedet for at indlæse poster bare for at tælle dem. AnyAsync() er endnu hurtigere end COUNT, når du kun har brug for at kontrollere, om noget findes.
// 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 1Masseindsættelser med AddRange
Brug AddRange til at tilføje flere entiteter på én gang. EF Core samler INSERT-operationerne i færre ture til databasen, styret af MaxBatchSize hos udbyderen.
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 til databasefunktioner
EF.Functions stiller databasespecifikke funktioner til rådighed (LIKE, datodele, fuldtekstsøgning), som EF Core oversætter til SQL i stedet for at evaluere i hukommelsen.
// 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();Diagnosticering af langsomme forespørgsler
Aktivér logning af EF Core-forespørgsler for at se den genererede SQL. Brug EnableSensitiveDataLogging() under udvikling for at se parameterværdierne.
builder.Services.AddDbContext<AppDbContext>(opt =>
opt.UseSqlServer(connStr)
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging() // dev only!
.EnableDetailedErrors()); // dev only!I praksis: Optimeret listeendepunkt
Et listeendepunkt, der er klar til produktion, kombinerer AsNoTracking, projektion, indekser og sideinddeling for maksimal ydeevne.
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 });
});Hurtigt tjek
Hvad er den største fordel ved EF.CompileAsyncQuery sammenlignet med en almindelig LINQ-forespørgsel?
Opsummering: Kompilerede forespørgsler og ydeevne
Vigtige pointer:
AsNoTracking(): spring ændringssporing over ved skrivebeskyttede forespørgsler – den hurtigste nemme gevinstEF.CompileAsyncQuery: forkompilér ofte kørte forespørgsler til delegater- Projektion med
Select: hent kun de nødvendige kolonner - Korrekte indekser (
HasIndex) forbedrer forespørgselsplaner markant - Sideinddel med
Skip/Take; brugAnyAsynctil at kontrollere, om noget findes - Aktivér logning af forespørgsler under udvikling for at opdage langsom eller uventet SQL
Lær C# med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 93
- Lektioner
- 346
Ofte stillede spørgsmål
Er lektionen “Kompilerede forespørgsler og ydeevne” gratis?
Ja — hele teksten til “Kompilerede forespørgsler og ydeevne” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af C# Academy-kurset, skal du opgradere til CoddyKit PRO. C# Academy-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Kompilerede forespørgsler og ydeevne”?
Forbedr forespørgslers ydeevne med EF.CompileQuery, AsNoTracking og projektion med Select. Du øver dig i C# Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på C# Academy?
Der kræves ingen tidligere erfaring. C# Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 3 af 4.
Hvor lang tid tager lektionen “Kompilerede forespørgsler og ydeevne”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne C# Academy-lektion?
Ja. Alle C# Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- Eager, Lazy og Explicit Loading
- Rå SQL, stored procedures og interpolation
- Kompilerede forespørgsler og ydeevne
- Globale forespørgselsfiltre og owned entities