Hemen her backend geliştiricinin kariyerinde en az bir kez yaşadığı klasik bir sahne vardır: Son siparişleri ve siparişi veren müşterinin adını listeleyen bir API uç noktası (endpoint) yazarsın. Kendi bilgisayarında (localhost) test veritabanında 4-5 kayıt varken sayfa 6 milisaniyede şimşek gibi açılır.
Kodu canlıya (production) alırsın. Gerçek kullanıcılar sayfaya girip 100 siparişi listelediği anda PostgreSQL sunucusunun CPU'su %100'e vurur, veritabanı bağlantı havuzu (connection pool) tıkanır ve sayfa 3-4 saniyede zor açılmaya başlar.
Kodda hiçbir sözdizimi hatası yoktur ama veritabanını gizlice boğan en meşhur performans tuzağına düşmüşsündür: N+1 Query (Sorgu) Problemi!
1. N+1 Query Tuzağı Nasıl Oluşur?
Son 100 siparişi ve her siparişin sahibini getirmek için yazılan şu masum görünümlü koda bakalım:
// ❌ N+1 TUZAĞI: Siparişler için 1 sorgu + döngü içinde her sipariş için 100 ayrı sorgu!
const orders = await db.query("SELECT * FROM orders LIMIT 100"); // -> 1. Sorgu (1)
for (const order of orders) {
// Döngünün her adımında veritabanına YENİ bir ağ isteği (network roundtrip) atılır!
order.user = await db.query("SELECT * FROM users WHERE id = $1", [order.user_id]); // -> 100 Sorgu (N)
}Gel basit bir matematik yapalım:
- İlk satırda
Nadet siparişi çekmek için 1 sorgu attık (N = 100). - Ardından
fordöngüsünün içinde, 100 siparişin her birinin kullanıcısını bulmak için veritabanına 100 ayrı sorgu daha attık. - Toplam: Tek bir kişinin sayfayı yenilemesiyle veritabanına tam
100 + 1 = 101ayrı SQL sorgusu gitti! (Sayfaya aynı anda 50 kişi girerse veritabanına saniyede 5.050 sorgu çarpar!).
Asıl Katil Sorgu Süresi Değil, Ağ Gecikmesidir (Network Roundtrip)
users tablosunda id üzerinde Primary Key indeksi olduğu için PostgreSQL tek bir sorguyu 0.2 milisaniyede çözebilir. Ancak uygulama sunucun ile veritabanı sunucun arasındaki her gidiş-dönüş (TCP Network Roundtrip) bulut ortamında ortalama 3 ile 5 milisaniye sürer:
- 2 sorgu atarsan:
2 x 4ms = 8msağ beklemesi. - 101 sorgu atarsan:
101 x 4ms = 404mssadece yolda geçen boş bekleme süresi!
2. Çözüm: Eager Loading (JOIN veya WHERE id IN)
Veritabanına 100 kere kapıyı çalıp "12 numaralı kullanıcı kim?", "15 numaralı kullanıcı kim?" diye tek tek sormak yerine; tek seferde tüm siparişlerdeki kullanıcı ID'lerini toplayıp 1 veya 2 sorguda tüm veriyi çekmeye Eager Loading (İstekli Yükleme) denir.
Yöntem A: Saf SQL LEFT JOIN (Toplam 1 Sorgu)
SELECT orders.*, users.name, users.email
FROM orders
LEFT JOIN users ON orders.user_id = users.id
LIMIT 100;Yöntem B: ORM'lerde include / with Kullanımı (Toplam 2 Sorgu)
Prisma, Drizzle ORM, Laravel (Eloquent) veya Django kullanıyorsan N+1 problemini çözmek kelimenin tam anlamıyla tek satırdır:
// ✅ PRISMA ÇÖZÜMÜ: `include` ile ilişkili veriyi tek seferde toplu çeker
const orders = await prisma.order.findMany({
take: 100,
include: {
user: true, // <- Arka planda SELECT * FROM users WHERE id IN (...) çalıştırır!
},
});
// ✅ DRIZZLE ORM ÇÖZÜMÜ: `with` kullanımı
const orders = await db.query.orders.findMany({
limit: 100,
with: {
user: true,
},
});Bu kodu yazdığında ORM arka planda sadece şu 2 sorguyu çalıştırır:
SELECT * FROM orders LIMIT 100;SELECT * FROM users WHERE id IN (12, 15, 19, 44, ...);
Ve gelen kullanıcıları uygulama belleğinde (RAM) mikrosaniyeler içinde siparişlerle eşleştirir. 101 sorgu anında 2 sorguya düşer!
Uyarı: GraphQL ve İç İçe Component Tuzaklarına Dikkat!
N+1 problemi her zaman açık bir for döngüsü içinde görünmez. GraphQL resolver'larında veya React Server Components / Laravel Blade şablonlarında her satır bileşeninin kendi içinde order.getUser() çağırması (Lazy Loading) en sinsi N+1 kaynağıdır. Geliştirme ortamında ORM'inin SQL loglamasını (log: ['query']) mutlaka açık tut!
İnteraktif N+1 Query Teşhis Aracı & Kısa Video
Kendi projende N+1 darboğazı olup olmadığını adım adım kontrol etmek için hazırladığım interaktif teşhis aracını hemen kullanabilirsin:
İnteraktif Yol Haritası & Araç
Junior Backend Developer 2026
2026'da junior backend pozisyonuna girmek isteyen biri gerçekten neyi bilmeli, neyi sonraya bırakabilir — ilanlardaki buzzword tuzaklarını ayıklayarak.
SQL mi NoSQL mi?
Altı soruya cevap ver, projene hangi tür veritabanının uyduğunu ve nedenini söyleyeyim.
Bunu da oku
- CZTROrtalık Çok Karışık: Backend Geliştirmeye Başlarken Hangi Dil ve Framework Seçilmeli? (2026 Karar Rehberi)
Ortalık Çok Karışık: Backend Geliştirmeye Başlarken Hangi Dil ve Framework Seçilmeli? (2026 Karar Rehberi)
25 Ekim 2026 · 5 dk okuma - CZTRPHP'de Yeni CVE-2026-115560 Zafiyeti: session.upload_progress ve Deserialization Analizi
PHP'de Yeni CVE-2026-115560 Zafiyeti: session.upload_progress ve Deserialization Analizi
24 Ekim 2026 · 3 dk okuma