Django ORM, veritabanı işlemlerini Python sınıflarıyla yönetmemizi sağlayan devasa bir araçtır.
Özellikle orta ve büyük ölçekli projelerde, veritabanına atılan sorgu sayısı (query count) uygulamanın dar boğazı haline gelebilir.
Bu makalede, Django’nun performans optimizasyonunda kullanılan bazı araçları birlikte inceleyelim.
İlişkili Verilerde Hız ve N+1 Sorunu
Django’da bir modelden veri çekerken, o modele bağlı başka bir modelin (ForeignKey veya OneToOne) alanına erişmek istediğinizde Django, veritabanına yeni bir sorgu gönderir. Eğer 100 tane nesneyi bir döngüde dönüyorsanız ve her birinin ilişkili verisine erişiyorsanız, veritabanına toplam 101 sorgu gider. Buna N+1 Problemi denir.
select_related: SQL JOIN Mantığı
select_related, veritabanı seviyesinde bir SQL JOIN işlemi yapar. İlişkili nesneyi ana sorgu ile tek seferde çeker.
ForeignKey ve OneToOneField ilişkilerinde (tekil sonuç dönen ilişkiler) kullanılır. Böylece tek bir SQL sorgusu ile tüm veriyi getirir.
prefetch_related: Python Seviyesinde Birleştirme
prefetch_related, JOIN yerine her tablo için ayrı birer sorgu atar ve sonuçları Python tarafında eşleştirir.
ManyToManyField ve ters ForeignKey (bir yazara ait tüm kitaplar gibi) ilişkilerinde kullanılır. Böylece JOIN işlemi yapıldığında satır sayısının katlanarak artacağı (Cartesian product) durumlarda performansı korur.
Karmaşık Mantıklar
Bazen veritabanından veri çekerken, belirli koşullara göre farklı değerler üretmek istersiniz. Bunu Python tarafında yapmak yerine veritabanı seviyesinde çözmek (SELECT CASE WHEN …) çok daha hızlıdır.
Django’da When objesi, Case fonksiyonu içerisinde kullanılır.
Örnek Senaryo: İndirim Hesaplama
Bir e-ticaret siteniz olduğunu ve ürünlerin stok durumuna göre bir etiket atamak istediğinizi düşünelim.
Bu işlem veritabanı tarafında bittiği için, binlerce satırda saniyeler içinde sonuç alırsınız.
Güçlü ve Esnek
Bazı durumlarda bir QuerySet’in içinde başka bir QuerySet çalıştırmanız gerekir. Django’daki Subquery sınıfı tam olarak bunu sağlar. OuterRef ise içteki sorgunun, dıştaki sorgunun bir alanına (örneğin ana tablo ID’si) referans vermesine yarar.
Neden Bu Yapılar Çok Önemli?
Hız (Latency): Python kodu veritabanından çok daha yavaştır. Veriyi çekip Python’da if-else yapmak yerine veritabanına “bana şu koşula uygun veriyi ver” demek milisaniyeler kazandırır.
Bellek Yönetimi: select_related kullanmazsanız, her nesne için yeni bir veritabanı bağlantısı veya işlemi açılır. Büyük döngülerde bu durum sunucuyu kilitleyebilir.
Ölçeklenebilirlik: 100 satırda fark etmeyeceğiniz performans kaybı, 1 milyon satırda uygulamanızın çökmesine neden olabilir.
Temiz Kod: İş mantığının (business logic) bir kısmını veritabanı seviyesinde (ORM ile) halletmek, kodun daha okunabilir ve yönetilebilir olmasını sağlar.
Performanslı bir Django uygulaması için kural basittir: Veritabanına mümkün olduğunca az kez git, gittiğinde ihtiyacın olan her şeyi tek seferde al.
Ayrıca bu sorguların arka planda hangi SQL’leri ürettiğini görmek için Django Debug Toolbar kütüphanesini projenize dahil etmeniz ve sorgu sayılarını takip etmeniz son derece yerinde bir karar olacaktır.



