Lazy Loading vs Eager Loading: N+1 Problemi, Performans ve Production Best Practices
Bu rehberde Lazy Loading vs Eager Loading konusunu ileri seviyede ele alıyoruz. Özellikle Hibernate N+1 problemi, JOIN FETCH, EntityGraph ve production ortamında performans optimizasyonlarını öğreneceksiniz.
- N+1 problemi = performans katili
- Default: LAZY → Optimize ederek ilerle
- JOIN FETCH & EntityGraph → kritik çözümler
N+1 Problemi Nedir?
N+1 problemi, Lazy Loading kullanılırken en sık karşılaşılan performans problemidir.
Örnek senaryo:
List<Order> orders = orderRepository.findAll();
for (Order order : orders) {
System.out.println(order.getItems().size());
}
Bu durumda:
- 1 adet ana sorgu (orders)
- N adet alt sorgu (items)
Çözüm 1 — JOIN FETCH
En yaygın ve güçlü çözüm JOIN FETCH kullanmaktır.
@Query("SELECT o FROM Order o JOIN FETCH o.items")
List<Order> findAllWithItems();
Avantajları
- Tek sorguda tüm veri çekilir
- N+1 problemi ortadan kalkar
Dikkat Edilmesi Gerekenler
- Pagination ile birlikte kullanımı zor olabilir
- Çok fazla join performansı düşürebilir
Çözüm 2 — EntityGraph
Daha esnek ve temiz bir çözüm: EntityGraph
@EntityGraph(attributePaths = {"items"})
List<Order> findAll();
Avantajları
- Declarative yapı (annotation bazlı)
- Dinamik fetch kontrolü
- Pagination ile uyumlu
Çözüm 3 — DTO Projection (En Temiz Yaklaşım)
En performanslı yöntem: sadece ihtiyaç duyulan veriyi çekmek
@Query("SELECT new com.app.dto.OrderDto(o.id, o.name) FROM Order o")
List<OrderDto> findOrders();
Neden Önemli?
- Gereksiz veri çekilmez
- Memory kullanımı azalır
- En hızlı yöntemdir
Benchmark Senaryosu (Gerçekçi Yaklaşım)
10.000 kayıt üzerinden yapılan tipik karşılaştırma:
| Yöntem | Sorgu Sayısı | Ortalama Süre |
|---|---|---|
| Lazy (N+1) | 10001 | 1200 ms |
| JOIN FETCH | 1 | 180 ms |
| EntityGraph | 1 | 170 ms |
| DTO Projection | 1 | 90 ms |
Production Best Practices 🚀
- Default olarak LAZY kullan
- EAGER kullanmaktan kaçın
- N+1 problemini her zaman loglardan kontrol et
- JOIN FETCH sadece gerektiğinde kullan
- EntityGraph ile esnek yapı kur
- DTO projection ile minimum veri çek
- Pagination + fetch kombinasyonuna dikkat et
Sonuç
Lazy vs Eager tartışması tek başına yeterli değildir. Asıl önemli olan:
- N+1 problemini yönetmek
- Doğru fetch stratejisini seçmek
- Gerçek kullanım senaryosuna göre optimize etmektir
Modern uygulamalarda en doğru yaklaşım: LAZY + DTO + gerektiğinde optimize