SQL JOIN TÜRLERİ VE FARKI

Veri Akademi8 dk okuma
İki kesişen daireli düz Venn şeması, kesişim koyu kırmızı dolu, dış hilaller soluk pembe, beyaz arka plan

INNER JOIN her zaman LEFT JOIN'den hızlıdır — bu, SQL dünyasında en sık tekrarlanan yanılgılardan biri. Gerçek şu ki performans farkı sorgu planına, indekslere ve veri dağılımına bağlıdır; JOIN türünün kendisi tek başına hızı belirlemez. Üstelik JOIN türlerini sadece "satır eşleştirme" olarak görmek, NULL davranışını ve cartesian patlama riskini gözden kaçırmanıza yol açar. Bu yazıda her JOIN türünün gerçekte ne yaptığını, hangi durumda NULL ürettiğini ve hangi sorgunun sessizce milyonlarca satır döndürebileceğini göreceksiniz.

1. INNER JOIN: Eşleşmeyen satır yok

INNER JOIN, iki tablodaki sadece eşleşen satırları döndürür. Eşleşme yoksa satır kaybolur — sessizce. Bu davranış, özellikle raporlamada veri kayıplarına neden olabilir.

Örnek olarak musteriler ve siparisler tablolarını düşünün. Sipariş vermemiş müşterileri görmek istiyorsanız INNER JOIN ile asla göremezsiniz: konunun temel referansı konuya derinlemesine bir bakış sağlar.

  • Sol tablodaki eşleşmeyen kayıtlar düşer
  • Sağ tablodaki eşleşmeyen kayıtlar düşer
  • NULL anahtar değerleri eşleşme olarak sayılmaz (NULL = NULL her zaman UNKNOWN'dır)

"INNER JOIN daha hızlıdır" iddiası bazen doğru, bazen yanlıştır. Optimizer eşleşmeyen satırları erkenden eleyebileceği için bazı senaryolarda LEFT JOIN'den hızlı çalışır. Ancak indeks doğru kurulmuşsa fark çoğu zaman ölçülemez seviyededir.

Beş JOIN türünün yan yana mini Venn şemaları: INNER, LEFT, RIGHT, FULL OUTER ve CROSS, her birinde farklı bölge dolu

2. LEFT JOIN ve sessizce gelen NULL'lar

LEFT JOIN, soldaki tablonun tüm satırlarını korur; sağda eşleşme yoksa o sütunlar NULL döner. Yanılgıların büyük kısmı bu NULL'ları doğru yorumlayamamaktan kaynaklanır.

LEFT JOIN tablo akışı: solda üç satır kırmızı dolu sol tablo, sağda NULL etiketli bir satır içeren eşleşme tablosu, ortada akış oku

Klasik tuzak: WHERE koşulunu sağ taraftaki sütuna uygulamak. Şu sorguya bakın:

SELECT * FROM musteriler m LEFT JOIN siparisler s ON m.id = s.musteri_id WHERE s.tutar > 100

Bu sorgu aslında INNER JOIN gibi davranır. Çünkü sağ tabloda NULL olan satırlar s.tutar > 100 koşulunu geçemez. Doğru yazım, koşulu ON bloğuna almaktır:

  • ON koşulu: eşleşme öncesi filtre — NULL kayıtları korur
  • WHERE koşulu: eşleşme sonrası filtre — NULL kayıtları düşürür

3. RIGHT JOIN gerçekten gerekli mi?

RIGHT JOIN, LEFT JOIN'in simetriğidir. Pratikte neredeyse hiç kullanılmaz çünkü tabloların yerini değiştirip LEFT JOIN yazmak daha okunabilirdir. Yine de bazı otomatik oluşturulmuş sorgularda görebilirsiniz.

Bir RIGHT JOIN gördüğünüzde aklınızdaki ilk soru şu olmalı: bu sorguyu yazan kişi neden tabloların sırasını değiştirmek istemedi? Genellikle cevap, sorgunun makine tarafından üretilmiş olmasıdır.

4. FULL OUTER JOIN: İki taraflı NULL

FULL OUTER JOIN, her iki taraftaki eşleşmeyen satırları da korur ve eksik kalan sütunları NULL ile doldurur. Veri uyuşmazlıklarını tespit etmek için en güçlü araçlardan biridir.

Örnek bir kullanım: iki farklı sistemden gelen müşteri listelerini karşılaştırmak. Hangi kayıtlar sadece A sistemde, hangileri sadece B sistemde var? FULL OUTER JOIN tek sorguda bunu çıkarır:

  1. Her iki tarafta da bulunan kayıtlar normal eşleşir
  2. Sadece sol tarafta olan kayıtlar sağ sütunlar NULL olarak gelir
  3. Sadece sağ tarafta olan kayıtlar sol sütunlar NULL olarak gelir

MySQL FULL OUTER JOIN'i doğrudan desteklemez; bunun yerine LEFT ve RIGHT JOIN'leri UNION ile birleştirmek gerekir. PostgreSQL, SQL Server ve Oracle yerel destek sunar.

5. CROSS JOIN ve cartesian patlama riski

CROSS JOIN, iki tablonun kartezyen çarpımını döndürür: soldaki her satır, sağdaki her satırla eşleşir. 1.000 × 1.000 = 1.000.000 satır. 10.000 × 10.000 = 100 milyon. Bu sessiz bir performans bombasıdır.

CROSS JOIN kartezyen patlama: solda küçük 3x3 grid, sağda devasa 9x9 patlamış grid, boyut farkı belirgin

Asıl tehlike kasıtlı CROSS JOIN'ler değildir — onları yazan zaten ne yaptığını bilir. Asıl tehlike, JOIN koşulunu unuttuğunuz INNER JOIN'lerdir:

SELECT * FROM siparisler s, musteriler m

Bu sorgu eski sözdiziminde virgül ile yazıldığında, ON koşulu yoksa, üstü kapalı bir CROSS JOIN'e dönüşür. ANSI JOIN sözdizimine geçmek bu hatayı büyük ölçüde önler çünkü JOIN anahtar kelimesi ON ifadesini zorlar.

6. SELF JOIN ve hiyerarşik veriler

SELF JOIN bir tablonun kendisiyle birleştirilmesidir. Çalışan-yönetici ilişkisi, kategori-üst kategori yapısı veya birbirine bağlı sipariş zinciri gibi durumlarda kullanılır. Teknik olarak ayrı bir JOIN türü değildir; INNER, LEFT veya FULL olarak uygulanabilir.

Tek tabloda yöneticinin adını bulmak için tabloyu kendisine bağlarsınız:

  • Aynı tablo iki farklı takma adla referans edilir
  • JOIN koşulu çalışanın yonetici_id'si ile diğer satırın id'sini eşler
  • En tepedeki yönetici için LEFT JOIN kullanmak gerekir, aksi takdirde o satır düşer

7. JOIN türünü seçerken sorulması gereken sorular

Hangi JOIN'i kullanacağınıza karar verirken performansı değil, veri ihtiyacınızı önceliklendirin. Sıralı düşünme şöyle olabilir:

  1. Eşleşmeyen kayıtları görmem gerekiyor mu? Evet ise OUTER JOIN.
  2. Hangi tablonun tüm kayıtlarını koruyacağım? Sol mu, her ikisi mi?
  3. NULL kontrolü hangi sütunda yapılacak? Bu kararı sorguyu yazarken verin, sonra değil.
  4. JOIN koşulu olmadan bir tablo bağlıyor muyum? Bu durum cartesian üretir, kasıtlı olduğundan emin olun.

SQL sorgu tasarımı, indeksleme ve sorgu planı okuma konularını derinlemesine öğrenmek için SQL için detaylı eğitim üzerinden ilerleyebilirsiniz.

8. Performans hakkında gerçek

"INNER her zaman daha hızlı" cümlesini bir kenara bırakın. Modern bir veritabanı motorunun optimizer'ı, JOIN türünü değil, mevcut indeksleri, satır tahminlerini ve istatistikleri kullanarak plan üretir. Aynı sorgu farklı veri dağılımında farklı plan üretebilir.

Performans farkı çoğu zaman JOIN türünden değil, şu faktörlerden kaynaklanır:

  • JOIN sütununda indeks var mı?
  • İstatistikler güncel mi?
  • WHERE koşulu erken filtreleme yapıyor mu?
  • Tablo boyutları ve satır tahminleri doğru mu?

Bir sorgunun yavaş çalıştığını düşündüğünüzde önce EXPLAIN veya EXPLAIN ANALYZE ile sorgu planını inceleyin. JOIN türünü değiştirmek bazen yardımcı olur, ama bu nadiren ilk çözümdür. Pratikte indeks eklemek veya WHERE koşulunu yeniden yazmak çok daha sık fark yaratır. Daha fazla sorgu örneği ve egzersiz için SQL eğitimi sayfasını inceleyebilirsiniz.

Sonuç olarak JOIN seçimi bir hız meselesi değil, bir doğruluk meselesidir. Yanlış JOIN, hızlı ama yanlış sonuçlar üretir; doğru JOIN, doğru sonuçlar üretir ve performansını siz indekslerle ayarlarsınız.

Sıkça Sorulan Sorular

INNER JOIN gerçekten LEFT JOIN'den her zaman daha hızlı mıdır?

Hayır. Bu yaygın bir yanılgıdır. JOIN türü tek başına hızı belirlemez; sorgu planı, indeksler, satır sayısı ve veri dağılımı belirleyicidir. Bazı senaryolarda INNER JOIN eşleşmeyen satırları erken eleyerek hızlanabilir, ancak doğru indekslenmiş bir LEFT JOIN ile farkı ölçmek genelde imkansızdır.

LEFT JOIN sonrası WHERE koşulu eklemek neden sorguyu INNER JOIN'e çevirebilir?

Çünkü WHERE, JOIN tamamlandıktan sonra çalışır. Sağ tablodaki sütun NULL ise ve WHERE koşulu bu sütunu test ediyorsa, NULL satırlar elenir ve sonuç INNER JOIN davranışı gösterir. Bunu önlemek için filtreyi ON bloğuna almak veya IS NULL kontrolü eklemek gerekir.

FULL OUTER JOIN MySQL'de neden çalışmaz?

MySQL tarihsel olarak FULL OUTER JOIN'i desteklememiştir. Aynı sonucu elde etmek için LEFT JOIN ve RIGHT JOIN sonuçlarını UNION ile birleştirmek gerekir. PostgreSQL, SQL Server ve Oracle ise FULL OUTER JOIN'i yerel olarak destekler.

CROSS JOIN yanlışlıkla nasıl oluşur?

En sık eski virgül-sözdiziminde JOIN koşulu unutulduğunda oluşur. Örneğin FROM tablo1, tablo2 yazıp WHERE içine eşleşme koşulu eklemezseniz kartezyen çarpım üretilir. ANSI JOIN sözdizimi kullanmak bu hatayı büyük ölçüde önler çünkü JOIN anahtar kelimesi ON ifadesini gerektirir.

NULL anahtar değerleri JOIN'de eşleşir mi?

Hayır. SQL'de NULL = NULL ifadesi TRUE değil UNKNOWN döner. Bu nedenle anahtar sütunu NULL olan satırlar hiçbir JOIN türünde diğer NULL satırlarla eşleşmez. Bu davranışı aşmak için IS NOT DISTINCT FROM gibi özel operatörler veya COALESCE kullanılır.

SELF JOIN ayrı bir JOIN türü müdür?

Hayır. SELF JOIN bir tablonun kendisine bağlanmasıdır ve INNER, LEFT veya FULL olarak uygulanabilir. Çalışan-yönetici, kategori-üst kategori gibi hiyerarşik veriler için kullanılır. Aynı tabloya iki farklı takma ad verilerek çalıştırılır.

JOIN performansını iyileştirmek için ilk yapılması gereken nedir?

JOIN türünü değiştirmek değil, sorgu planını incelemektir. EXPLAIN veya EXPLAIN ANALYZE ile planı görmek, sonra JOIN sütunlarında uygun indeksler oluşturmak ve istatistiklerin güncel olduğundan emin olmak çoğunlukla en büyük farkı yaratır.

RIGHT JOIN ne zaman tercih edilmeli?

Pratikte neredeyse hiç. Tabloların sırasını değiştirip LEFT JOIN yazmak daha okunabilirdir ve aynı sonucu verir. RIGHT JOIN genellikle makine tarafından üretilen sorgularda veya çok karmaşık çoklu JOIN zincirlerinde belirli bir sıralamayı korumak için görülür.