Entity Framework Core'da Performansı Katlayın: AsNoTracking ve Compiled Queries
Yavaş çalışan EF Core sorgularından bıktınız mı? İki pratik teknikle veritabanı performansınızı nasıl zirveye taşıyabileceğinizi öğrenin.

Selamlar sevgili geliştirici dostum!
Entity Framework Core (EF Core) projelerimizde işimizi inanılmaz kolaylaştıran harika bir ORM. Ancak projeler büyüdükçe ve trafik arttıkça "Ya bu sorgu neden bu kadar yavaş çalışıyor?" ya da "Sunucu belleği neden tavan yaptı?" gibi dertlerle karşılaşmaya başlayabiliriz.
Neyse ki EF Core bize performans optimizasyonu için harika araçlar sunuyor. Bu yazıda, backend projelerinde hemen uygulayabileceğin iki devasa performans silahını inceleyeceğiz: AsNoTracking ve Compiled Queries.
Hazırsan, kahveni al ve performans yolculuğuna başlayalım! ☕
1. EF Core'un Gizli Yükü: Change Tracker ve AsNoTracking
EF Core, varsayılan olarak veritabanından çektiğin her entity'i arkada Change Tracker mekanizması ile izler. Bu izleme sayesinde nesne üzerinde bir değişiklik yapıp SaveChangesAsync() dediğinde EF Core neyin değiştiğini şıp diye anlar ve uygun UPDATE sorgusunu oluşturur.
Peki ya sen veriyi sadece okumak (örneğin bir dashboard veya liste ekranı için) istiyorsan? Değişiklik yapmayacağın bir veriyi EF Core'un izlemesi boşuna bellek (RAM) ve CPU tüketimidir.
İşte tam bu noktada AsNoTracking() imdadımıza yetişiyor.
// ❌ Kötü Pratik: Değişiklik yapılmayacak ama Change Tracker çalışıyor
public async Task<List<Product>> GetAllProductsAsync()
{
return await _context.Products.ToListAsync();
}
// ✅ İyi Pratik: İzleme kapatıldı, bellek ve işlemci tasarrufu sağlandı!
public async Task<List<Product>> GetAllProductsReadOnlyAsync()
{
return await _context.Products
.AsNoTracking()
.ToListAsync();
}İpucu: Eğer projenin genelinde sadece okuma yapan bir servis yazıyorsan, DbContext seviyesinde QueryTrackingBehavior.NoTracking ayarını da varsayılan yapabilirsin.
2. Sık Çalışan Sorgular İçin Hız Treni: Compiled Queries
EF Core bir LINQ sorgusunu çalıştıracağı zaman şu adımlardan geçer:
1. LINQ ifadesini analiz eder (Expression Tree parsing).
2. Bunu veritabanının anlayacağı SQL sorgusuna dönüştürür.
3. SQL sorgusunu veritabanına gönderir.
Eğer uygulanda saniyede onlarca kez çalışan aynı yapıda bir sorgu varsa (örneğin GetById sorguları), EF Core'un her seferinde LINQ'i SQL'e çevirmesi ciddi bir maliyet yaratır.
Compiled Queries (Derlenmiş Sorgular) sayesinde sorgunun SQL'e dönüştürülmüş halini önbelleğe (cache) alabiliriz. Böylece EF Core analiz adımını pas geçer ve doğrudan veritabanına gider!
Gel bunu koda dökelim:
public class ProductRepository
{
private readonly AppDbContext _context;
// ⚡ Sorgumuzu static ve compiled olarak tanımlıyoruz
private static readonly Func<AppDbContext, int, Task<Product?>> GetProductByIdCompiled =
EF.CompileAsyncQuery((AppDbContext context, int id) =>
context.Products
.AsNoTracking()
.FirstOrDefault(p => p.Id == id));
public ProductRepository(AppDbContext context)
{Cpu
_context = context;
}
public async Task<Product?> GetProductByIdAsync(int id)
{
// Derlenmiş sorguyu çağırıyoruz
return await GetProductByIdCompiled(_context, id);
}
}
Burada hem `EF.CompileAsyncQuery` hem de `AsNoTracking` gücünü birleştirdik! Bu kullanım, yüksek trafikli API endpoint'lerinde gözle görülür bir milisaniye (ms) düşüşü sağlayacaktır.Ne Zaman Hangisini Kullanmalı?
AsNoTracking: Yalnızca listeleyeceğin, raporlayacağın veya istemciye (frontend) direkt DTO olarak döneceğin tüm read-only sorgularda mutlaka kullanmalısın.Compiled Queries: Sistemde çok sık çağrılan, parametresi değişen ama sorgu kalıbı hep aynı kalan kritik endpoint'lerde tercih etmelisin.
Özet
Küçük dokunuşlar, yüksek yük altındaki sistemlerde devasa performans farkları yaratır. Mevcut projendeki AsNoTracking eksiklerini tamamlayarak bile sunucu kaynaklarında anında rahatlama görebilirsin.
Sen projelerinde EF Core optimizasyonu için hangi yöntemleri kullanıyorsun? Yorumlarda buluşalım! 👇
Kodlu günler!