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
Includeedildiğinde, JOIN'ler satır sayısını katlayarak büyütebilir. Bu durumdaAsSplitQuery()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.