0Pricing
C# Academy · Lektion

Kompilierte Abfragen und Performance

Steigern Sie die Abfrageleistung mit EF.CompileQuery, AsNoTracking und Projektionen mit Select.

Kompilierte Abfragen und Performance ist eine kostenlose C# Academy-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des C# Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der C# Academy-Kurs umfasst insgesamt 4 Lektionen.

Kompilierung von EF-Core-Abfragen

Jedes Mal, wenn EF Core eine LINQ-Abfrage ausführt, muss es den Ausdrucksbaum analysieren, ihn in SQL übersetzen und validieren. Bei häufig ausgeführten Pfaden summiert sich dieser Overhead. EF Core stellt mehrere Werkzeuge bereit, um ihn zu minimieren.

AsNoTracking für schreibgeschützte Abfragen

AsNoTracking() überspringt die Registrierung im Change Tracker. Für schreibgeschützte Abfragen (API-Antworten, Berichte) ist dies die größte einfach umsetzbare Optimierung – typischerweise 2–5-mal schneller und mit geringerem Speicherverbrauch.

// 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();

Kompilierte Abfragen

EF.CompileAsyncQuery kompiliert eine LINQ-Abfrage vorab in einen Delegaten. Die Übersetzung erfolgt einmal beim Start; spätere Aufrufe überspringen den Kompilierungsschritt vollständig.

// 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 mit Select für bessere Performance

Projizieren Sie immer genau auf die benötigten Felder. Die Auswahl eines DTOs anstelle einer vollständigen Entität reduziert die abgerufenen Spalten, die Netzwerklast und den Druck auf den Garbage Collector.

// 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

Indexhinweise und Optimierung von Raw-Abfragen

EF Core berücksichtigt die Datenbankindizes, die Sie mit HasIndex() konfigurieren. Zusammengesetzte Indizes, gefilterte Indizes und inkludierte Spalten beeinflussen allesamt die Performance des Abfrageplans.

// 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();

Seitennummerierung mit Skip und Take

Seitennummerieren Sie große Ergebnismengen immer. Skip und Take werden in SQL-OFFSET/FETCH übersetzt und verhindern, dass Tausende von Zeilen in den Arbeitsspeicher geladen werden.

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

Effizient zählen

Verwenden Sie CountAsync() oder AnyAsync(), anstatt Datensätze nur zum Zählen zu laden. AnyAsync() ist sogar schneller als COUNT, wenn Sie lediglich die Existenz prüfen möchten.

// 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

Bulk Inserts mit AddRange

Verwenden Sie AddRange, um mehrere Entitäten auf einmal hinzuzufügen. EF Core bündelt die INSERT-Anweisungen in weniger Roundtrips. Die Größe der Batches wird beim Provider über MaxBatchSize gesteuert.

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

Datenbankfunktionen mit EF.Functions

EF.Functions stellt datenbankspezifische Funktionen (LIKE, Datumsteile, Volltextsuche) bereit, die EF Core in SQL übersetzt, anstatt sie im Arbeitsspeicher auszuwerten.

// 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();

Langsame Abfragen diagnostizieren

Aktivieren Sie die EF-Core-Abfrageprotokollierung, um das generierte SQL anzuzeigen. Verwenden Sie in der Entwicklung EnableSensitiveDataLogging(), um Parameterwerte sichtbar zu machen.

builder.Services.AddDbContext<AppDbContext>(opt =>
    opt.UseSqlServer(connStr)
       .LogTo(Console.WriteLine, LogLevel.Information)
       .EnableSensitiveDataLogging() // dev only!
       .EnableDetailedErrors());     // dev only!

Praxisbeispiel: Optimierter Listenendpunkt

Ein produktionsreifer Listenendpunkt kombiniert AsNoTracking, Projektion, Indizes und Seitennummerierung für maximale Performance.

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 });
});

Kurzer Check

Was ist der wichtigste Vorteil von EF.CompileAsyncQuery gegenüber einer regulären LINQ-Abfrage?

Zusammenfassung: Kompilierte Abfragen und Performance

Wichtigste Erkenntnisse:

  • AsNoTracking(): Change Tracker bei schreibgeschützten Abfragen überspringen – die schnellste einfach umsetzbare Optimierung
  • EF.CompileAsyncQuery: häufig ausgeführte Abfragen vorab in Delegaten kompilieren
  • Projektion mit Select: nur die benötigten Spalten abrufen
  • Geeignete Indizes (HasIndex) verbessern Abfragepläne erheblich
  • Mit Skip/Take seitennummerieren; AnyAsync für Existenzprüfungen verwenden
  • In der Entwicklung die Abfrageprotokollierung aktivieren, um langsames oder unerwartetes SQL zu erkennen

Häufig gestellte Fragen

Ist die Lektion „Kompilierte Abfragen und Performance“ kostenlos?

Ja — der vollständige Text von „Kompilierte Abfragen und Performance“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des C# Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der C# Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Kompilierte Abfragen und Performance“?

Steigern Sie die Abfrageleistung mit EF.CompileQuery, AsNoTracking und Projektionen mit Select. Du übst C# Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um C# Academy zu starten?

Keine Vorkenntnisse erforderlich. C# Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.

Wie lange dauert die Lektion „Kompilierte Abfragen und Performance“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser C# Academy-Lektion Code schreiben und ausführen?

Ja. Jede C# Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Eager-, Lazy- und Explicit-Loading
  2. Rohes SQL, Stored Procedures und Interpolation
  3. Kompilierte Abfragen und Performance
  4. Globale Abfragefilter und Owned Entities
← Zurück zu C# Academy