Entity Framework Core güçlü bir ORM'dir, ancak kullanışsız şekilde yazılan sorgular ciddi performans sorunlarına yol açabilir. Bu makale, EF Core 10'da performans optimizasyonları hakkında detaylı bilgi verir.
N+1 Problem
N+1 problemi, en yaygın performans sorunlarından biridir:
// ❌ KÖTÜ: N+1 sorgusu
var products = await context.Products.ToListAsync();
foreach (var product in products)
{
var category = await context.Categories
.FirstOrDefaultAsync(c => c.Id == product.CategoryId);
Console.WriteLine($"{product.Name} - {category.Name}");
}
// Bu kod: 1 sorgu + (N ürün) sorgu = N+1 sorgu
// ✅ İYİ: Eager loading
var products = await context.Products
.Include(p => p.Category)
.ToListAsync();
foreach (var product in products)
{
Console.WriteLine($"{product.Name} - {product.Category.Name}");
}
// Bu kod: 1 sorgu
AsNoTracking
Sadece okunan veriler için AsNoTracking() kullanın:
// ✅ AsNoTracking ile sadece okuma
var reportData = await context.Products
.AsNoTracking()
.Where(p => p.IsActive)
.Select(p => new { p.Id, p.Name, p.Price })
.ToListAsync();
// Change tracker overhead'ı olmaz, daha hızlı
Raw SQL Queries
Karmaşık sorgular için raw SQL kullanmak sorunlu değildir:
// ✅ Raw SQL, parametrelendirilmiş
var categoryId = 1;
var products = await context.Products
.FromSqlInterpolated($@"
SELECT * FROM Products
WHERE CategoryId = {categoryId}
AND Price > 100
ORDER BY Price DESC
")
.ToListAsync();
// Parametrelendirilmiş sorgular SQL injection'tan korur
Büyük veri setleri için pagination zorunludur:
public class PaginationParams
{
public int Page { get; set; } = 1;
public int PageSize { get; set; } = 10;
}
public async Task<PaginatedResult<ProductDto>> GetProductsAsync(PaginationParams @params)
{
var totalCount = await context.Products.CountAsync();
var items = await context.Products
.AsNoTracking()
.OrderByDescending(p => p.CreatedAt)
.Skip((@params.Page - 1) * @params.PageSize)
.Take(@params.PageSize)
.Select(p => new ProductDto
{
Id = p.Id,
Name = p.Name,
Price = p.Price
})
.ToListAsync();
return new PaginatedResult<ProductDto>
{
Items = items,
TotalCount = totalCount,
Page = @params.Page,
PageSize = @params.PageSize
};
}
Indexing Stratejisi
Database seviyesinde indeksler, sorgu performansını çok artırır:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>()
.HasIndex(p => p.CategoryId)
.HasName("IX_Product_CategoryId");
modelBuilder.Entity<Product>()
.HasIndex(p => p.CreatedAt)
.HasName("IX_Product_CreatedAt");
modelBuilder.Entity<Product>()
.HasIndex(p => new { p.IsActive, p.Price })
.HasName("IX_Product_Active_Price");
}
Query Optimization Tips
- Select kullanın: Sadece ihtiyaç duyduğunuz alanları seçin
- Filtering'i database'de yapın: LINQ to Objects değil, LINQ to SQL kullanın
- Batch işlemleri: Toplu update/delete için batch processing yapın
- Async/await: Always async queries for scalability
Sonuç
EF Core 10, performans optimizasyonları için güçlü araçlar sunar. Doğru teknikler kullanarak, scalable ve hızlı uygulamalar yazabilirsiniz.