IN, EXISTS, NOT EXISTS ile Subquery
Giriş — Varlık Kontrolü
"Bu müşteri sipariş vermiş mi?", "Bu ürün hiç satılmış mı?" — bu tür sorular varlık kontrolü gerektirir. IN ve EXISTS farklı yaklaşımlarla aynı sonucu üretir ama performans profilleri farklıdır.
IN vs EXISTS
-- IN: Subquery bir liste döndürür, dış sorgu o listede kontrol eder
SELECT first_name FROM customers
WHERE customer_id IN (SELECT customer_id FROM orders);
-- EXISTS: Her dış satır için subquery çalışır, TRUE/FALSE döndürür
SELECT first_name FROM customers c
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.customer_id);İkisi de aynı sonucu verir ama:
IN: Subquery sonucunu bellekte tutar → küçük sonuç setlerinde hızlı
EXISTS: İlk eşleşmede durur → büyük tablolarda hızlı, index varsa çok verimli
NOT IN vs NOT EXISTS
-- NOT IN: Listede OLMAYAN kayıtlar
SELECT first_name FROM customers
WHERE customer_id NOT IN (
SELECT customer_id FROM orders WHERE customer_id IS NOT NULL
);
-- ⚠️ NULL kontrolü zorunlu!
-- NOT EXISTS: Eşleşme OLMAYAN kayıtlar (NULL-safe)
SELECT first_name FROM customers c
WHERE NOT EXISTS (
SELECT 1 FROM orders o WHERE o.customer_id = c.customer_id
);
-- ✅ NULL sorunu yok💡 İpucu: "Olmayanları bulma" senaryolarında NOT EXISTS tercih et: - NULL-safe (NOT IN'in NULL tuzağı yok) - Index varsa genellikle daha hızlı - Okunabilir: "var olmayan kayıtlar" mantığını doğrudan ifade eder
Performans Karşılaştırması
| Senaryo | IN | EXISTS |
|---|---|---|
| Subquery az satır döndürüyor | ✅ Hızlı | ✅ Hızlı |
| Subquery çok satır döndürüyor | ⚠️ Bellek sorunu | ✅ Hızlı (erken çıkış) |
| NOT versiyonu + NULL olasılığı | ⚠️ Tuzaklı | ✅ Güvenli |
| Index var | ✅ Hızlı | ✅ Çok hızlı |
Gerçek Dünya Örnekleri
-- En az bir "Elektronik" kategorisi ürünü alan müşteriler
SELECT DISTINCT c.first_name, c.last_name
FROM customers c
WHERE EXISTS (
SELECT 1 FROM orders o
INNER JOIN order_items oi ON o.order_id = oi.order_id
INNER JOIN products p ON oi.product_id = p.product_id
INNER JOIN categories cat ON p.category_id = cat.category_id
WHERE o.customer_id = c.customer_id
AND cat.category_name = 'Elektronik'
);
-- Hiç satış yapılmamış kategoriler
SELECT category_name FROM categories cat
WHERE NOT EXISTS (
SELECT 1 FROM products p
INNER JOIN order_items oi ON p.product_id = oi.product_id
WHERE p.category_id = cat.category_id
);EXISTS İpuçları
-- EXISTS subquery'de SELECT ne döndürdüğü önemsiz:
WHERE EXISTS (SELECT 1 FROM ...) -- ✅ Geleneksel
WHERE EXISTS (SELECT * FROM ...) -- ✅ Çalışır (optimizer optimize eder)
WHERE EXISTS (SELECT NULL FROM ...) -- ✅ Çalışır
-- Hepsi aynı performans — EXISTS sadece satır varlığını kontrol ederÖzet
IN: subquery sonuç listesi küçükse ve NULL riski yoksa kullan
EXISTS: büyük tablolarda, index varsa, NULL-safe senaryo için tercih et
NOT EXISTS > NOT IN: NULL güvenliği ve performans açısından üstün
EXISTS subquery'de
SELECT 1yazmak yeterli — sütun seçimi önemsizModern MySQL optimizer IN'i EXISTS'e dönüştürebilir ama explicit yazmak daha güvenli
AI Asistan
Sorularını yanıtlamaya hazır