ORM Performansı & Veri Erişim Stratejileri 3 dk okuma 21 okunma

Lazy Loading vs. Eager Loading: Performans Dengesi

Lazy Loading, ilişkili veriyi yalnızca erişildiğinde yükler; kaynak verimliliği sağlar ancak dikkatsiz kullanımda N+1 sorgu problemine yol açar. Eager Loading ise ilişkili veriyi ana sorguyla birlikte getirir; N+1'i önler ancak gereksiz veri çekme riski taşır. Doğru denge, verinin gerçekten kullanılıp kullanılmayacağına göre belirlenir.

Lazy Loading vs. Eager Loading: Performans Dengesi

Lazy Loading vs. Eager Loading: Performans Dengesi

ORM'lerde ilişkili verilerin nasıl yükleneceği, uygulama performansını doğrudan etkileyen en kritik kararlardan biridir. Lazy Loading (tembel yükleme) ve Eager Loading (hevesli yükleme), aynı soruna iki farklı yaklaşım sunar. Ancak "hangisi daha iyi?" sorusunun tek bir cevabı yoktur; doğru seçim, verinin ne zaman ve ne sıklıkla kullanıldığına bağlıdır.


1. Lazy Loading: İhtiyaç Duyulduğunda Yükle

Lazy Loading, ilişkili veriyi yalnızca o veriye erişildiğinde yükler. Ana nesne çekildiğinde, ilişkili nesneler bellekte yüklenmez; ilk erişim anında veritabanına ayrı bir sorgu gönderilir .

Avantajları:

  • Kaynak Verimliliği: İlişkili veri hiç kullanılmayacaksa, boşuna yüklenmez. Bellek ve sorgu maliyeti düşer .

  • Seçici Kullanım: Yalnızca belirli bir alt kümenin ihtiyaç duyduğu veriler için idealdir .

Dezavantajları:

  • N+1 Sorgu Problemi: En büyük risk budur. Bir liste çekip her öğe için ilişkili veriye erişirseniz, her öğe için ayrı bir sorgu çalışır. 100 kayıt, 101 sorgu demektir .

  • Öngörülemez Gecikme: Sorgular, kodun neresinde erişim olursa orada tetiklenir; performans sorunu geliştirme sırasında fark edilmeyebilir .

EF Core'da Lazy Loading:
Microsoft.EntityFrameworkCore.Proxies paketi ve UseLazyLoadingProxies() ile etkinleştirilir. Navigasyon özelliklerinin virtual olması gerekir .


2. Eager Loading: Peşinen Yükle

Eager Loading, ana sorgu çalıştırıldığında ilişkili veriyi de aynı anda yükler. EF Core'da Include ve ThenInclude metotlarıyla belirtilir .

Avantajları:

  • N+1'i Önler: Tüm veri tek bir sorguda (veya birkaç sorguda) geldiği için tekrarlı sorgular oluşmaz .

  • Öngörülebilir Performans: Veritabanına kaç sorgu gideceği baştan bellidir.

Dezavantajları:

  • Gereksiz Veri Çekme: İhtiyaç duyulmayan ilişkili veriler de yüklenebilir; bellek ve bant genişliği israf edilir .

  • Kartezyen Patlama (Cartesian Explosion): Çok sayıda koleksiyon Include edildiğinde, JOIN'ler satır sayısını katlayarak büyütebilir. Bu durumda AsSplitQuery() ile sorguyu bölmek gerekebilir .


3. Doğru Denge: Ne Zaman Hangisi?

Seçim, verinin kullanım desenine göre yapılmalıdır.

Eager Loading Kullanın:

  • İlişkili verinin kesinlikle kullanılacağı durumlarda (ör. sipariş detay sayfasında müşteri ve kalemler birlikte gösterilecekse) .

  • Liste ekranlarında, her öğe için ilişkili veriye erişilecekse.

  • N+1 riski taşıyan döngülerde.

Lazy Loading Kullanın:

  • İlişkili verinin nadiren veya koşullu olarak kullanıldığı durumlarda (ör. liste ekranında sadece isim gösteriliyor, detay tıklanınca ilişkili veri çekilecekse) .

  • Ana nesnenin çekilmesi hızlı olmalı ve ilişkili veri çoğu zaman gerekmeyecekse.

En İyi Yaklaşım: Projeksiyon (DTO)
Lazy/Eager tartışmasının ötesinde, en verimli yöntem yalnızca ihtiyaç duyulan alanları seçmektir. EF Core'da Select ile DTO'ya projeksiyon yapmak, hem gereksiz veri çekmeyi önler hem de Change Tracker yükünü ortadan kaldırır .

csharp

// Sadece gerekli alanlar, ilişkili veriyle birlikte
var orders = await context.Orders
    .Where(o => o.CustomerId == id)
    .Select(o => new OrderDto
    {
        Id = o.Id,
        Total = o.Total,
        CustomerName = o.Customer.Name  // JOIN ile tek sorguda
    })
    .ToListAsync();

4. En İyi Pratikler

Pratik Açıklama
Lazy Loading'i varsayılan yapmayın N+1 riski nedeniyle üretimde önerilmez; bilinçli olarak, sadece gerekli yerlerde açın .
Sıcak yollarda Eager Loading kullanın Liste ve detay ekranlarında Include ile ilişkili veriyi peşinen yükleyin.
Projeksiyonu tercih edin Include yerine Select ile DTO'ya projeksiyon, daha az veri ve daha az izleme yükü demektir .
AsSplitQuery() değerlendirin Çok sayıda koleksiyon içeren Include'larda kartezyen patlamayı önlemek için sorguyu bölün .
Sorgu sayısını izleyin Geliştirmede SQL log'larını açın; tekrarlayan sorgular N+1'in işaretidir .

Sonuç

Lazy Loading ve Eager Loading, birbirinin alternatifi değil, farklı senaryoların araçlarıdır. Lazy Loading, ilişkili verinin nadiren kullanıldığı durumlarda kaynak verimliliği sağlar; ancak N+1 problemine karşı dikkatli olunmalıdır. Eager Loading, ilişkili verinin kesinlikle kullanılacağı durumlarda N+1'i önler; ancak gereksiz veri çekme riskini beraberinde getirir. En sağlıklı yaklaşım, her ikisini de bilinçli kullanmak ve mümkün olduğunda projeksiyon (DTO) ile yalnızca ihtiyaç duyulan veriyi çekmektir. Unutmayın: Performans, "ne kadar az sorgu" değil, "ne kadar az gereksiz iş" sorusuyla başlar.

Tüm yazılar Soru ya da yorumun mu var? Yaz