← Kursa Dön
📄 Text · 30 min

JOIN vs Subquery — Performans Karşılaştırması

Giriş — Aynı Sonuç, Farklı Yollar

Birçok sorgu hem JOIN hem subquery ile yazılabilir. Hangisi daha iyi? Cevap: duruma göre değişir. Bu derste iki yaklaşımı karşılaştırıp ne zaman hangisini kullanacağını öğreneceğiz.


Aynı Sorgu — İki Farklı Yol

Soru: Sipariş vermiş müşterilerin listesi

-- JOIN ile
SELECT DISTINCT c.first_name, c.last_name
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id;

-- Subquery ile (IN)
SELECT first_name, last_name
FROM customers
WHERE customer_id IN (SELECT DISTINCT customer_id FROM orders);

-- Subquery ile (EXISTS)
SELECT first_name, last_name
FROM customers c
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.customer_id);

Her üçü de aynı sonucu verir — ama performans ve okunabilirlik farkı var.


JOIN Avantajları

  1. İki tablodan da sütun seçebilirsin:

-- JOIN: Her iki tablodan sütunlar
SELECT c.first_name, o.order_id, o.total_amount
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id;

-- Subquery: Sadece dış tablodan sütunlar
SELECT first_name FROM customers WHERE customer_id IN (SELECT customer_id FROM orders);
-- orders'tan sütun alamazsın!
  1. Genellikle daha performanslı (MySQL optimizer JOIN'leri iyi optimize eder)

  2. Çoklu tablo birleştirmede daha okunabilir:

-- JOIN: Net ve okunabilir
SELECT c.first_name, p.product_name
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id
JOIN order_items oi ON o.order_id = oi.order_id
JOIN products p ON oi.product_id = p.product_id;

Subquery Avantajları

  1. "Olmayanları bulma" daha doğal:

-- EXISTS (genellikle en hızlı yol)
SELECT first_name FROM customers c
WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.customer_id);

-- LEFT JOIN + IS NULL
SELECT c.first_name FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
WHERE o.order_id IS NULL;

-- NOT IN (NULL tuzağına dikkat!)
SELECT first_name FROM customers
WHERE customer_id NOT IN (SELECT customer_id FROM orders WHERE customer_id IS NOT NULL);
  1. Aggregate sonucunu filtrede kullanma:

-- Ortalama fiyattan pahalı ürünler
SELECT product_name, price FROM products
WHERE price > (SELECT AVG(price) FROM products);
-- JOIN ile bunu yazmak daha karmaşık
  1. Bağımsız alt sorgular daha okunabilir olabilir.


Performans Karşılaştırması

SenaryoJOININ SubqueryEXISTS Subquery
Eşleşen satırları getirme✅ Hızlı⚠️ Orta✅ Hızlı
Eşleşmeyenleri bulma✅ (LEFT JOIN + IS NULL)⚠️ (NOT IN, NULL dikkat)✅ (NOT EXISTS)
Çok büyük sonuç seti⚠️ Yavaşlayabilir
İki tablodan sütun
-- EXPLAIN ile performans kontrolü
EXPLAIN SELECT c.first_name FROM customers c 
INNER JOIN orders o ON c.customer_id = o.customer_id;

EXPLAIN SELECT first_name FROM customers 
WHERE customer_id IN (SELECT customer_id FROM orders);

💡 İpucu: Modern MySQL (8.0+) optimizer, birçok subquery'yi otomatik olarak JOIN'e dönüştürür. Performans farkı azalmıştır ama yine de EXPLAIN ile kontrol etmek en doğrusudur.


Pratik Kılavuz

DurumÖnerilen
İki tablodan sütun gerekiyorJOIN
Sadece varlık/yokluk kontrolüEXISTS
Aggregate sonucuyla karşılaştırmaSubquery
"Olmayan" kayıtları bulmaNOT EXISTS veya LEFT JOIN + IS NULL
Birden fazla tablo birleştirmeJOIN
Karmaşık hesaplama sonucu filtrelemeSubquery

Gerçek Dünya Örneği

-- Ortalamanın üstünde harcama yapan müşteriler
-- (Subquery + JOIN hibrit)
SELECT 
    c.first_name,
    c.last_name,
    SUM(o.total_amount) AS total_spent
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id
WHERE o.status = 'delivered'
GROUP BY c.customer_id, c.first_name, c.last_name
HAVING SUM(o.total_amount) > (
    SELECT AVG(total_amount) FROM orders WHERE status = 'delivered'
);
-- JOIN ile tabloları birleştir, subquery ile ortalamayı hesapla

Özet

  • Aynı sonuç hem JOIN hem subquery ile üretilebilir

  • JOIN: iki tablodan sütun gerektiğinde, çoklu tablo birleştirmede tercih et

  • EXISTS/NOT EXISTS: varlık/yokluk kontrolünde, "olmayan" kayıtlarda tercih et

  • Subquery: aggregate karşılaştırma, bağımsız hesaplama için kullanışlı

  • Modern MySQL optimizer birçok subquery'yi JOIN'e dönüştürür — performans farkı azaldı

  • EXPLAIN ile her iki yaklaşımı karşılaştır ve en hızlı olanı seç