← Kursa Dön
📄 Text · 35 min

Correlated vs Non-Correlated Subquery

Giriş — Bağımlı ve Bağımsız Alt Sorgular

Subquery'ler ikiye ayrılır: dış sorgudan bağımsız çalışanlar (non-correlated) ve dış sorgunun her satırına bağlı çalışanlar (correlated). Bu fark hem mantık hem performans açısından kritiktir.


Non-Correlated (Bağımsız) Subquery

Dış sorgudan bağımsız, tek başına çalıştırılabilir:

-- Subquery tek başına çalışır — dış sorgudan bağımsız
SELECT product_name, price
FROM products
WHERE price > (SELECT AVG(price) FROM products);
-- (SELECT AVG(price) FROM products) tek başına çalışır: 13009.99
-- BİR KERE çalışır, sonucu cache'lenir

Correlated (Bağımlı) Subquery

Dış sorgunun her satırı için tekrar çalışır:

-- Her ürünün kendi kategorisindeki ortalamadan pahalı olup olmadığı
SELECT p.product_name, p.price, p.category_id
FROM products p
WHERE p.price > (
    SELECT AVG(p2.price)
    FROM products p2
    WHERE p2.category_id = p.category_id  -- ← Dış sorgudaki p'ye referans!
);
-- Her ürün için subquery yeniden çalışır (farklı category_id ile)

Nasıl çalışır:

  1. Dış sorgu ilk satırı alır (product_id = 1, category_id = 2)

  2. Subquery çalışır: AVG(price) WHERE category_id = 2 → 36999.99

  3. Karşılaştır: 54999.99 > 36999.99? Evet → dahil et

  4. İkinci satır... (tekrar)


Karşılaştırma

ÖzellikNon-CorrelatedCorrelated
BağımlılıkBağımsızDış sorguya bağımlı
Çalışma sayısı1 kereHer dış satır için 1 kere
Performans✅ Genellikle hızlı⚠️ Yavaş olabilir
KullanımSabit karşılaştırmaSatır bazlı karşılaştırma

Correlated Subquery Örnekleri

-- Her kategorideki en pahalı ürün
SELECT p.product_name, p.price, p.category_id
FROM products p
WHERE p.price = (
    SELECT MAX(p2.price) FROM products p2 WHERE p2.category_id = p.category_id
);

-- Her müşterinin son siparişi
SELECT o.customer_id, o.order_id, o.order_date, o.total_amount
FROM orders o
WHERE o.order_date = (
    SELECT MAX(o2.order_date) FROM orders o2 WHERE o2.customer_id = o.customer_id
);

-- Ortalamanın üstünde sipariş veren müşteriler (correlated)
SELECT c.first_name, c.last_name
FROM customers c
WHERE (
    SELECT AVG(o.total_amount) FROM orders o WHERE o.customer_id = c.customer_id
) > (SELECT AVG(total_amount) FROM orders);

Correlated Subquery → JOIN Dönüşümü

Correlated subquery'leri JOIN ile yeniden yazmak genellikle daha performanslıdır:

-- Correlated subquery (yavaş olabilir)
SELECT p.product_name, p.price
FROM products p
WHERE p.price = (
    SELECT MAX(p2.price) FROM products p2 WHERE p2.category_id = p.category_id
);

-- JOIN ile (genellikle daha hızlı)
SELECT p.product_name, p.price
FROM products p
INNER JOIN (
    SELECT category_id, MAX(price) AS max_price
    FROM products GROUP BY category_id
) AS cat_max ON p.category_id = cat_max.category_id AND p.price = cat_max.max_price;

SELECT'te Correlated Subquery

-- Her müşterinin sipariş sayısı (correlated scalar subquery)
SELECT c.first_name, c.last_name,
    (SELECT COUNT(*) FROM orders o WHERE o.customer_id = c.customer_id) AS order_count,
    (SELECT MAX(total_amount) FROM orders o WHERE o.customer_id = c.customer_id) AS max_order
FROM customers c;
-- Her müşteri için 2 subquery çalışır — 10 müşteri = 20 subquery çağrısı!

-- JOIN alternatifi (daha verimli):
SELECT c.first_name, c.last_name,
       COUNT(o.order_id) AS order_count,
       MAX(o.total_amount) AS max_order
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.first_name, c.last_name;

Sıkça Yapılan Hatalar

  1. Correlated subquery'nin N kere çalıştığını bilmemek: 10.000 satırlık tabloda 10.000 kere subquery = çok yavaş.

  2. JOIN ile yazılabilecek correlated subquery: Çoğu correlated subquery JOIN'e dönüştürülebilir ve genellikle daha hızlıdır.

  3. SELECT'te çoklu correlated subquery: Her biri ayrı ayrı çalışır. JOIN + GROUP BY ile tek sorguda çöz.


Özet

  • Non-correlated subquery: dış sorgudan bağımsız, 1 kere çalışır, genellikle hızlı

  • Correlated subquery: dış sorguya bağımlı, her satır için çalışır, N kez çalışır

  • Correlated subquery'ler güçlü ama performans maliyetli — mümkünse JOIN'e çevir

  • EXISTS doğası gereği correlated'dır ve genellikle iyi optimize edilir