SQL JOIN TÜRLERİ VE FARKI

İ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.

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

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

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.

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.

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.

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

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.

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.