Entity Framework Core: N+1 Sorgu Problemini Çözmek
Entity Framework Core kullanırken sık karşılaşılan bir performans sorunu vardır: bir ana veriyi çekerken, her ilişkili veri için ayrı bir sorgu yapılması. Örneğin 10 yazarın kitaplarını listelemek için 1 sorgu yazarlar için, sonra 10 sorgu her yazar için kitapları çekmek anlamına gelir. Toplamda 11 sorgu. buna N+1 diyoruz.
Aşağıdaki modelleri düşün:
1public class Author2{3public int Id { get; set; }4public string Name { get; set; }5public ICollection<Book> Books { get; set; }6}78public class Book9{10public int Id { get; set; }11public string Title { get; set; }12public int AuthorId { get; set; }13}Yanlış Yaklaşım (N+1 Sorunu):
1var authors = _context.Authors.ToList();2foreach (var author in authors)3{4var books = _context.Books.Where(b => b.AuthorId == author.Id).ToList();5// Her döngüde ayrı sorgu!6}Bu kod 1 + N sorgu çalıştırır. 100 yazar varsa 101 sorgu!
İlişkili verileri önceden yükle:
1var authors = _context.Authors.Include(a => a.Books).ToList();23foreach (var author in authors)4{5Console.WriteLine($"{author.Name}: {author.Books.Count} kitap");6}Çıktı:
1Orhan Pamuk: 5 kitap2Ahmet Ümit: 3 kitapArtık 1 sorgu yeterli. SQL'de `LEFT JOIN` kullanılır.
Sadece ihtiyacın olan alanları çek:
1var result = _context.Authors.Select(a => new2{3a.Name,4BookCount = a.Books.Count()5}).ToList();67foreach (var item in result)8{9Console.WriteLine($"{item.Name}: {item.BookCount} kitap");10}11[/cod]1213Bu yöntem veri tabanında `COUNT` işlemini yapar. Daha hızlıdır.1415Veriyi sadece okuyacaksan tracking'i kapat:1617[kod]18var authors = _context.Authors.AsNoTracking().Include(a => a.Books).ToList();Tracking kapalı olunca bellek kullanımı azalır.
N+1 sorgusu veritabanını gereksiz yere yükler. Include() ile ilişkili veriyi önceden yükle, Select() ile sadece gerekli alanları çek, AsNoTracking() ile bellek tasarrufu yap. Böylece 1 sorgu yeterli olur ve uygulamanın performansı artar.
0 yorum