Ana içeriğe geç
Kesit SQL
Orta · Uygulama Geliştirme

Uygulamadan SQL'e: parametreli sorgu, ORM ve N+1

Kod içinden veritabanına güvenli ve verimli erişim.

Uygulamada aç, 5 alıştırmayı çözÜcretsiz, hesap gerekmez, kurulum yok.

Bu sayfa dersin okuma sürümüdür. Metin bir kutuyu çalıştırmanı ya da adıma geçmeni söylüyorsa dersi uygulamada aç.

Parametreli sorgu: tek doğru yol

Kullanıcı girdisini sorgu metnine birleştirmek, SQL injection açığının kaynağıdır. Bunun yerine sorgu bir kez yazılır, değerler parametre olarak ayrı gönderilir. Veritabanı parametreyi her zaman veri olarak görür, kod olarak çalıştırmaz.

# Yanlış (Python) — girdi sorguya birleştiriliyor
cur.execute("SELECT * FROM customers WHERE email = '" + email + "'")

# Doğru — parametre
cur.execute("SELECT * FROM customers WHERE email = %s", (email,))

// C# / ADO.NET
var cmd = new SqlCommand("SELECT * FROM customers WHERE email = @email", conn);
cmd.Parameters.AddWithValue("@email", email);

Parametreli sorguların bir faydası da plan önbelleğidir: aynı sorgu metni farklı değerlerle tekrar kullanılır.

ORM nedir?

Entity Framework, Hibernate, Django ORM, SQLAlchemy, Prisma gibi araçlar tabloları sınıflara eşler ve SQL'i senin yerine üretir. Hızlı geliştirme sağlar ama ürettiği SQL'i görmeden kullanmak performans sorunlarına yol açar. ORM kullanan iyi bir geliştirici, ürettiği SQL'i günlükte okuyabilir.

N+1 sorunu

Bir sayfada 50 müşteri ve her birinin sipariş sayısı gösterilecek. Saf bir ORM kodu önce müşterileri çeker (1 sorgu), sonra döngüde her müşteri için sipariş sayısını sorar (50 sorgu): toplam 51 sorgu. Her sorgu ağ gidiş-dönüşü demektir.

-- N+1: uygulama döngüsünde
SELECT customer_id, first_name FROM customers WHERE segment = 'Premium';
SELECT COUNT(*) FROM orders WHERE customer_id = 3;
SELECT COUNT(*) FROM orders WHERE customer_id = 7;
-- ... müşteri sayısı kadar
-- Çözüm: tek sorgu
SELECT c.customer_id,
       c.first_name,
       COUNT(o.order_id) AS siparis_sayisi
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.customer_id
WHERE c.segment = 'Premium'
GROUP BY c.customer_id, c.first_name;

ORM'lerde bunun karşılığı “eager loading”dir: Include() (EF), select_related / prefetch_related (Django), joinedload (SQLAlchemy).

Diğer iyi alışkanlıklar

Alıştırmalara geç (5)