SQL EXISTS ve IN farkı kısaca şöyle özetlenebilir: IN, bir değerin alt sorgunun ürettiği değer kümesinde bulunup bulunmadığını kontrol eder. EXISTS ise dış sorgunun o an değerlendirdiği satır için en az bir eşleşen kaydın varlığını sınar.
Bu nedenle seçim yalnızca “hangisi daha hızlı?” sorusuyla yapılmamalıdır. Alt sorgunun dış sorguyla ilişkili olup olmadığı, NULL değer ihtimali, alt sorgunun ürettiği sonuçların yapısı ve sorgunun ekip tarafından ne kadar kolay okunacağı birlikte değerlendirilmelidir. SQL alt sorgularının mantığını adım adım pekiştirmek isteyenler, asenkron yazılım video eğitimleri içinde sorgu kurma pratiği yapabilir.
Kısa cevap: IN mi, EXISTS mi kullanılmalı?
Alt sorgunun döndürdüğü sütun değerleriyle bir üyelik kontrolü yapmak istiyorsanız IN daha doğrudan bir anlatım sunar. Örneğin “müşterinin kimliği, sipariş veren müşterilerin kimlikleri arasında mı?” sorusu doğal olarak bir değer kümesi kontrolüdür.
“Bu müşteri için en az bir sipariş kaydı var mı?” sorusunda ise EXISTS mantıksal olarak daha açıklayıcı olabilir. Burada önemli olan alt sorgunun bir değer listesi üretmesinden çok, dış sorgudaki mevcut satırla eşleşen herhangi bir kaydın bulunmasıdır.
-- IN: sipariş veren müşterilerin kimliklerini küme olarak düşünür
SELECT c.customer_id, c.customer_name
FROM customers AS c
WHERE c.customer_id IN (
SELECT o.customer_id
FROM orders AS o
);
-- EXISTS: her müşteri için eşleşen sipariş var mı diye bakar
SELECT c.customer_id, c.customer_name
FROM customers AS c
WHERE EXISTS (
SELECT 1
FROM orders AS o
WHERE o.customer_id = c.customer_id
);
Müşteri ve sipariş tablolarında orders.customer_id ile customers.customer_id aynı ilişkiyi temsil ediyorsa bu iki sorgu pozitif eşleşme açısından aynı müşteri kümesini üretebilir. Ancak sorguların zihinsel modeli farklıdır: İlk sorgu “kimlikler arasında üyelik” derken, ikinci sorgu “bu müşteri için en az bir kayıt varlığı” der.
EXISTS her zaman IN ifadesinden hızlıdır ya da bunun tersi doğrudur şeklinde genel bir kural kurulamaz. Sonuç; kullanılan veritabanı motoruna, indekslere, veri dağılımına, sorgunun yazımına ve optimizer tarafından oluşturulan execution plan çıktısına bağlı olabilir. Performans önemliyse iki sorgunun planını incelemek, yalnızca sözdizimine bakarak karar vermekten daha güvenlidir.
IN ifadesi alt sorgudan dönen değerleri nasıl kontrol eder?

IN, bir sütundaki değerin sabit bir listeye veya alt sorgunun döndürdüğü tek sütunlu değerler kümesine üyeliğini kontrol eder. Aşağıdaki sorguda dış sorgudaki customer_id değerleri, alt sorgudan dönen sipariş sahibi müşteri kimlikleri arasında aranır:
SELECT customer_id, customer_name
FROM customers
WHERE customer_id IN (
SELECT customer_id
FROM orders
);
Alt sorgu mantıksal olarak bir değer kümesi üretir. Dış sorgu da customers tablosundaki her satır için kendi customer_id değerini bu kümede arar. Eşleşme varsa müşteri seçilir; eşleşme yoksa satır sonuç kümesine alınmaz.
Buradaki alt sorgunun birden fazla satır döndürmesi normaldir; önemli olan alt sorgunun tek bir sütun döndürmesidir. Aynı müşteri birden fazla sipariş vermişse alt sorguda aynı kimlik birden fazla kez bulunabilir, ancak IN açısından üyelik kontrolünün sonucu değişmez.
Alt sorgu NULL içerdiğinde pozitif eşleşmeler genellikle yine bulunabilir; fakat eşleşmeyen satırlarda SQL’in üç değerli mantığı nedeniyle sonuç doğrudan yalnızca “yanlış” olarak değerlendirilmez. Özellikle NOT IN kullanımında bu durum daha belirgin bir probleme dönüşür:
SELECT CASE
WHEN 5 NOT IN (2, NULL) THEN 'Eşleşmedi'
ELSE 'TRUE değil: FALSE veya UNKNOWN'
END AS sonuc;
Bu örnekte 5 değeri 2 değildir; ancak listede NULL bulunduğu için “5 NULL değildir” sonucu kesin olarak belirlenemez. Bu nedenle NOT IN kullanırken alt sorgunun NULL üretip üretmediği mutlaka kontrol edilmelidir.
EXISTS ve ilişkili alt sorgu dış sorguyla nasıl bağlanır?
Correlated subquery, yani ilişkili alt sorgu, dış sorgunun o anda değerlendirdiği satırdaki bir değeri kullanır. Aşağıdaki örnekte alt sorgu, her müşteri için orders tablosunda aynı customer_id değerine sahip en az bir sipariş bulunup bulunmadığını kontrol eder.
-- IN ile değer kümesinde üyelik kontrolü
SELECT c.customer_id, c.customer_name
FROM customers AS c
WHERE c.customer_id IN (
SELECT o.customer_id
FROM orders AS o
);
-- EXISTS ile her müşteri için eşleşen satırın varlığını kontrol etme
SELECT c.customer_id, c.customer_name
FROM customers AS c
WHERE EXISTS (
SELECT 1
FROM orders AS o
WHERE c.customer_id = o.customer_id
);
Her iki sorgunun beklenen sonucu, orders tablosunda en az bir eşleşen siparişi bulunan müşteri kayıtlarıdır. IN sürümü önce alt sorgunun ürettiği customer_id değerlerini bir küme gibi ele alır ve dış müşterinin bu kümenin içinde olup olmadığını sınar. EXISTS sürümü ise her dış customers satırı için alt sorguyu değerlendirerek eşleşen en az bir sipariş satırı bulunup bulunmadığına bakar.
Sonuçların aynı görünmesinin nedeni, iki sorgunun da aynı pozitif eşleştirme koşulunu kullanmasıdır: customers.customer_id ile orders.customer_id birbirine eşit olmalıdır. Ancak okunma biçimleri farklıdır. IN “Bu değer, dönen değerler arasında mı?” sorusunu sorarken, EXISTS “Bu müşteriyle ilişkili en az bir satır var mı?” sorusuna odaklanır.
| İfade | Temel soru | Alt sorgunun dış sorguyla ilişkisi |
|---|---|---|
IN |
Değer, alt sorgu sonucundaki kümede bulunuyor mu? | Alt sorgu çoğunlukla bağımsız okunabilir. |
EXISTS |
Eşleşen en az bir satır var mı? | Alt sorgu, c.customer_id = o.customer_id gibi bir koşulla dış satıra bağlanır. |
Burada c.customer_id alt sorgunun dışındaki tabloya, o.customer_id ise alt sorgunun içindeki tabloya aittir. Bu nedenle ikinci sorgu bağımsız bir alt sorgu değildir; dış sorgunun her müşterisi için yeniden anlam kazanan ilişkili bir alt sorgudur. SQL öncesi algoritmik düşünme becerinizi ölçmek için ücretsiz kodlama bilgisi testi üzerinden benzer koşul ve döngü mantıklarını çalışabilirsiniz.
Bu iki biçimden birinin her zaman daha hızlı olduğunu söylemek doğru değildir. Veritabanı motoru, indeksler, veri dağılımı ve sorgunun tamamı sonucu etkileyebilir. Tercih öncelikle ifade edilen mantığın okunabilirliğine göre yapılmalı, performans ihtiyacı varsa execution plan incelenmelidir.
NOT EXISTS ve NOT IN: NULL tuzağı neden önemlidir?

Olumsuz eşleşmelerde NOT IN kullanırken NULL değerlerine özellikle dikkat etmek gerekir. Örneğin orders.customer_id sütununda bazı siparişlerin herhangi bir müşteriye bağlanmadığı ve bu satırlarda NULL bulunduğu bir senaryo düşünelim.
-- Siparişi olmayan müşterileri NOT IN ile arama
SELECT c.customer_id, c.customer_name
FROM customers AS c
WHERE c.customer_id NOT IN (
SELECT o.customer_id
FROM orders AS o
);
-- Aynı amacı NULL'dan etkilenmeden NOT EXISTS ile ifade etme
SELECT c.customer_id, c.customer_name
FROM customers AS c
WHERE NOT EXISTS (
SELECT 1
FROM orders AS o
WHERE o.customer_id = c.customer_id
);
-- NOT IN kullanılacaksa NULL değerlerini alt sorguda filtreleme
SELECT c.customer_id, c.customer_name
FROM customers AS c
WHERE c.customer_id NOT IN (
SELECT o.customer_id
FROM orders AS o
WHERE o.customer_id IS NOT NULL
);
NOT IN içindeki alt sorgu sonucu bir NULL içerdiğinde, eşleşmeyen bazı karşılaştırmalar kesin olarak TRUE veya FALSE yerine UNKNOWN durumuna taşınabilir. WHERE koşulu yalnızca TRUE olan satırları döndürdüğü için beklenen müşteri listesi eksik, hatta boş görünebilir.
NOT EXISTS ise dış müşteriye ait gerçekten eşleşen bir sipariş satırı bulunup bulunmadığını kontrol eder. orders.customer_id değeri NULL olan bir satır, o.customer_id = c.customer_id koşulunu sağlamadığı için müşteriyle eşleşme olarak kabul edilmez. Bu nedenle olumsuz ilişkileri ifade ederken NULL davranışını açıkça düşünmek gerekir.
NOT IN tercih edilecekse alt sorguda IS NOT NULL filtresi kullanılabilir; ancak bunun güvenli olup olmadığı, sütunun anlamına ve sorgunun iş kuralına bağlıdır. Sadece sözdizimini değiştirmek yerine, “Bu müşterinin hiç siparişi yok mu?” sorusunu doğrudan ifade eden NOT EXISTS çoğu durumda daha okunabilir bir seçenek sunar.
Doğru seçimi yapmak için dört maddelik karar çerçevesi
IN ve EXISTS arasında seçim yaparken ilk soru “Hangisi daha hızlı?” olmamalıdır. Daha sağlam yaklaşım; alt sorgunun dış sorguyla ilişkisini, NULL ihtimalini, dönen veri kümesinin yapısını ve sorgunun ekip tarafından ne kadar kolay okunacağını birlikte değerlendirmektir.
- Alt sorgu dış sorguyla ilişkili mi? Alt sorgu, dış sorgudaki her satıra göre yeniden anlam kazanıyorsa
EXISTSveyaNOT EXISTSmantıksal olarak daha doğal okunabilir. Örneğin “Bu müşterinin en az bir siparişi var mı?” sorusunda alt sorgu, dış sorgudaki müşteriyle bağ kurar. Bu durum,EXISTSifadesinin her veritabanında otomatik olarak daha hızlı olduğu anlamına gelmez; yalnızca niyeti daha açık ifade edebilir. - Alt sorgu sonucunda
NULLçıkabilir mi? Özellikle olumsuz koşullarda bu kontrol kritik hâle gelir. Alt sorgunun döndürdüğü sütunNULLiçerebiliyorsaNOT IN, beklenmeyen biçimde hiçbir satır döndürmeyebilir. Böyle durumlardaNOT EXISTS, ilişkiyi açıkça kurduğu için daha güvenli bir seçenek olabilir. - Alt sorgu kaç satır ve nasıl bir değer kümesi döndürüyor? Küçük ve belirli bir değer kümesinde
IN, üyelik kontrolünü kolayca anlatır. Ancak satır sayısı tek başına karar ölçütü değildir. Büyük tablolar, veri dağılımı, indeksler ve optimizer’ın seçtiği plan birlikte incelenmelidir. - Yazım, ekip için hangi niyeti daha iyi anlatıyor? Sorgu yalnızca bugün çalışmamalı; birkaç ay sonra okunduğunda da amacını korumalıdır. Bir müşteri ile sipariş arasındaki ilişkiyi kontrol ediyorsanız
EXISTSdaha açıklayıcı olabilir. Sabit bir üyelik kümesini kontrol ediyorsanızINdaha kısa ve anlaşılır kalabilir.
| İfade türü | Temel mantık | NULL riski | Uygun senaryo | Dikkat noktası |
|---|---|---|---|---|
| IN | Bir değer, alt sorgu sonucundaki kümede bulunuyor mu? | Olumlu koşullarda genellikle daha sınırlı; karşılaştırılan değerlerin NULL durumu yine önemlidir. | Küçük veya açıkça tanımlanmış üyelik kümeleri | Alt sorgunun döndürdüğü sütunun anlamı ve veri tipi uyumlu olmalı |
| EXISTS | Dış satırla eşleşen en az bir kayıt var mı? | NULL değerinden çok eşleşme koşulunun doğruluğu önemlidir. | İlişkili alt sorgular ve varlık kontrolü | Dış sorguyla bağlantı koşulu doğru kurulmalı |
| NOT IN | Bir değer, alt sorgu sonucundaki kümede bulunmuyor mu? | Alt sorguda NULL varsa kritik risk taşır. | NULL içermediği garanti edilen değer kümeleri | NULL davranışı açıkça kontrol edilmeden kullanılmamalı |
| NOT EXISTS | Dış satırla eşleşen hiçbir kayıt yok mu? | İlişki koşulu üzerinden çalıştığı için olumsuz kontrollerde daha açık bir mantık sunar. | Siparişi olmayan müşteri veya kaydı bulunmayan ürün arama | Alt sorgu ile dış sorgu arasındaki eşleştirme eksiksiz yazılmalı |
Aynı müşteri-sipariş örneğinde dört adımı uygulamak
Örneğin customers tablosunda kayıtlı müşteriler, orders tablosunda ise siparişler bulunsun. “En az bir siparişi olan müşterileri getir” sorusunda alt sorgu, dış sorgudaki müşteriyle ilişkilidir. Bu nedenle aşağıdaki mantık okunabilirlik açısından güçlüdür:
SELECT c.customer_id, c.name
FROM customers AS c
WHERE EXISTS (
SELECT 1
FROM orders AS o
WHERE o.customer_id = c.customer_id
);
İlk adımda dış tabloyla ilişki olduğu görülür. İkinci adımda kontrol edilen alanın orders.customer_id olduğunu ve bu alandaki olası NULL değerlerin eşleşme üretmediğini değerlendiririz. Üçüncü adımda sipariş sayısına bakarız; fakat yalnızca “çok sipariş var” diyerek EXISTS için performans garantisi veremeyiz. Son olarak ekip açısından sorgunun “müşterinin siparişi var mı?” sorusunu doğrudan ifade edip etmediğine bakarız.
Aynı soruyu IN ile de yazabiliriz:
SELECT c.customer_id, c.name
FROM customers AS c
WHERE c.customer_id IN (
SELECT o.customer_id
FROM orders AS o
);
Burada IN, siparişlerden oluşan müşteri kimlikleri kümesine üyelik kontrolü yapar. Alt sorgu bağımsız bir değer kümesi gibi okunuyorsa bu yazım tercih edilebilir. “Siparişi olmayan müşteriler” aranıyorsa ise NOT IN kullanmadan önce alt sorgu sütununda NULL bulunmadığı doğrulanmalı; belirsizlik varsa NOT EXISTS değerlendirilmelidir.
Performans için sorgu planı ne zaman incelenmeli?
IN ve EXISTS arasında evrensel bir hız sıralaması yoktur. Aynı sorgu, farklı veritabanı motorlarında veya farklı veri dağılımlarında farklı planlarla çalışabilir. Tablo büyüklüğü, indeksler, filtrelerin seçiciliği, istatistiklerin güncelliği ve optimizer’ın maliyet tahminleri sonucu etkileyebilir. Resmî PostgreSQL dokümantasyonu da sorgu planlayıcısının satır tahminleri ve istatistikleri kullanarak plan seçtiğini, tahmini planın gerçekleşen çalışma verileriyle karşılaştırılabileceğini açıklar: PostgreSQL EXPLAIN dokümantasyonu.
Bu nedenle performans incelemesini şu sırayla yapmak daha sağlıklıdır:
- Önce sorgunun döndürdüğü sonucu kontrol edin. Özellikle
NOT INkullanılan sorgulardaNULLdavranışını ayrı test edin. - Sonucun mantıksal olarak doğru olduğundan emin olduktan sonra sorgunun okunabilirliğini değerlendirin. Daha hızlı olduğu varsayılan ama ilişki koşulu belirsiz bir yazım, bakım sırasında yeni hatalar oluşturabilir.
- Gerçek bir yavaşlık gözleniyorsa veritabanı motorunun uygun plan inceleme aracını kullanın. Tahmini satır sayıları ile gerçekleşen satır sayılarını, tarama türünü, indeks kullanımını ve gereksiz tekrarları karşılaştırın.
- İndeks veya sorgu değişikliğini aynı veri ve benzer çalışma koşullarıyla test edin. Yalnızca sorgunun metnine bakarak performans sonucu çıkarmayın.
Örneğin bir sorguda EXISTS kullanmak planlayıcının mutlaka daha az satır okuyacağı anlamına gelmez. Benzer şekilde IN ifadesini değiştirmek, indeks eksikliğinden veya seçiciliği düşük bir filtreden kaynaklanan sorunu tek başına çözmeyebilir. En doğru yaklaşım önce doğru mantık, sonra ölçüm ilkesidir.
Sık Sorulan Sorular
EXISTS her zaman IN'den daha mı hızlıdır?
Hayır. Performans; veritabanı motoruna, indekslere, tablo büyüklüğüne, veri dağılımına, filtre koşullarına ve optimizer’ın oluşturduğu execution plan’a bağlıdır. EXISTS bazı ilişkili alt sorgularda niyeti daha açık anlatabilir; bu, her durumda daha hızlı çalışacağı anlamına gelmez.
NOT IN neden NULL içeren alt sorgularda beklenmedik sonuç verir?
SQL’de NULL, normal bir değer gibi eşit veya eşitsiz kabul edilmez; karşılaştırma sonucu belirsiz olabilir. NOT IN alt sorgu sonucunda NULL ile karşılaştığında koşul beklenen şekilde doğruya dönmeyebilir ve sonuç kümesi boş kalabilir.
IN yerine EXISTS kullanmak sorgunun sonucunu değiştirir mi?
Doğru eşleştirme koşullarıyla ve aynı NULL varsayımları altında yazıldığında çoğu olumlu üyelik kontrolünde aynı sonucu verebilir. Ancak sorgular mantıksal olarak aynı kurulmazsa, özellikle yinelenen değerler, farklı NULL davranışları veya eksik ilişki koşulları sonuçları değiştirebilir.
Siparişi olmayan müşterileri bulurken NOT EXISTS neden daha güvenli bir seçenek olabilir?
NOT EXISTS, her müşteriyi sipariş tablosunda eşleşen bir kayıt olup olmadığı üzerinden değerlendirir. Bu yaklaşım, NOT IN içinde alt sorgudan gelen NULL değerlerinin tüm sonucu belirsizleştirme riskini azaltır ve “eşleşen sipariş yok” niyetini doğrudan ifade eder.
Doğru ifade, yalnızca kısa veya hızlı görünen değil; NULL davranışı, ilişki koşulu ve bakım ihtiyacı birlikte düşünüldüğünde amacını en net anlatan ifadedir.