Laravel Eloquent Kütüphanesinde Eager ve Lazy Loading Farkı

Eloquent ile tablolar arasında ilişkiler kurabiliyoruz. User(kişi) tablosuna bağlı Post(makale/yazı) tablosu bu Post tablosuna bağlı Comment(yorum) tablosu gibi.

Bu tablolardan aralarındaki ilişkileri kullanarak veri okurken dikkat etmemiz gereken bazı durumlar var. Eager(aç gözlü) ya da Lazy (tembel) yükleme yöntemlerinden birini seçmemiz gerekir.

Karmaşıklık ya da okuduğumuz verinin derinliği arttıkça bu tercih çok önemli olacaktır. Bu problem için N+1 sorgu problemi de denir.

Eager Loading

Bu yöntemde daha az sorgu kullanılacaktır, ana veri çekilirken alt veri de hemen ardından tek bir sorgu ile çekilecektir. Eager loading kullanmak için model sınıfına with metodunu eklemeniz yeterli olacaktır.

// Eager loading ile bütün kullanıcılar ve ilişikili Postlarını getir
User::with('posts')->all();
Lazy Loading

Bu yükleme yönteminde yapılacak ekstra bir şey yok. Normal bir şekilde Eloquent zinciri yazılır ve get, first ya da all gibi bir method ile sonlandırılır. İlişkili veri çağırıldığında gerekli query oluşturulur ve çalıştırılır.

Lazy loadingin neden tehlikeli olduğunu bir örnek ile açıklayayım.

Bir okul yönetim uygulamamız var ve veri yapımız/modellerimiz şu şekilde;

// Kurslarımız
class Course extends Model {
    public function lessons() {
        return $this->hasMany(Lesson::class);
    }
}

// Derslerimiz 
// her kurs için 10 ders olduğunu varsayalım
class Lesson extends Model {
    public function sections() {
        return $this->hasMany(Section::class);
    }
}

// Bölümler
// her ders için 15 bölüm olsun
class Section extends Model {
    public function topics() {
        return $this->hasMany(Topic::class);
    }
}

// konu başlıkları
// her bölüm için 5 başlık olsun
class Topic extends Model {
    
}

Gördüğünüz gibi kurslar->dersler->bölümler->başlıklar şeklinde bir yapımız var. Burada kursları listelediğimiz bir sayfamız olsun ve bu kursların altına da içinde bulunan konu başlıklarını da eklememiz istendi.

Eager loading hakkında fikrimiz olmadığı varsayarsak 20 kurs için 1 sorgu çalıştırdık ve döngüye soktuk. Her bir kurs için dersleri çağırdık 20 sorgu ile 200 ders geldi. Her ders için bölümleri çağırdık 200 sorgu ile 3000 bölüm geldi. ve sonunda her bölüm için başlıkları çağırdık ve 3000 sorgu çalıştırmış olduk. Toplamda 3221 sorgu çalışmış oldu.

Fakat eager loading ile bunların hepsi ilk anda birer sorgu ile çekilerek sorgu sayısı 4e kadar düşürebilir.

// lazy loading
$courses = Course::all();

// eager loading
$courses = Course::with('lessons.sections.topics')->get();


foreach ($courses as $course) {
    foreach ($course->lessons as $lesson) {
        foreach ($lesson->sections as $section) {
            foreach ($section->topics as $topic) {
                // başlıklar listelenebilir
            }
        }
    }
}

Eager loading her zaman avantajlı gibi duruyor ama öyle değil. Bazı durumlarda alt kademedeki verilerine koşullu olarak ihtiyaç duyulabilir. Yukarıdaki örnek için sadece satın alınmış kursların ders içeriğini göstermemiz istenebilir bu durumda eager loading ile bütün verileri çekmemiz gereksiz olacaktır. Fark ettiğiniz gibi binlerce kayıt bir anda geliyor ve bunları tutmak memory için büyük yük. Bunun yerine lazy loading ile uygun koşullarda alt kademelere inmek uygun olacaktır.


Yayımlandı

kategorisi

yazarı:

Etiketler:

Yorumlar

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir