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ı
İ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!Genellikle daha performanslı (MySQL optimizer JOIN'leri iyi optimize eder)
Ç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ı
"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);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şıkBağımsız alt sorgular daha okunabilir olabilir.
Performans Karşılaştırması
| Senaryo | JOIN | IN Subquery | EXISTS 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 gerekiyor | JOIN |
| Sadece varlık/yokluk kontrolü | EXISTS |
| Aggregate sonucuyla karşılaştırma | Subquery |
| "Olmayan" kayıtları bulma | NOT EXISTS veya LEFT JOIN + IS NULL |
| Birden fazla tablo birleştirme | JOIN |
| Karmaşık hesaplama sonucu filtreleme | Subquery |
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ç
AI Asistan
Sorularını yanıtlamaya hazır