JOIN anahtar sözcüğünü kullanma veya kullanmama


45

Aşağıdaki SQL sorguları aynıdır:

SELECT column1, column2
FROM table1, table2
WHERE table1.id = table2.id;

SELECT column1, column2
FROM table1 JOIN table2 
ON table1.id = table2.id;

Ve kesinlikle şimdiye kadar denedim her DBMS aynı sorgu planları sonuçlanır.

Ancak çoğu zaman, birinin kesinlikle diğerinden daha iyi olduğu görüşünü okudum ya da duyuyorum. Doğal olarak, bu iddialar hiçbir zaman bir açıklama ile kanıtlanmamaktadır.

Çalıştığım yerde, ikinci sürüm diğer devlerin çoğunluğu tarafından beğeniliyor gibi görünüyor ve ben de bu tarzı şaşırtmayı en aza indirgemeye meyilliyim. Ama yüreğimde, gerçekten birincisini düşünüyorum (o zamandan beri öğrendiğimden beri).

Bu formlardan biri nesnel olarak diğerinden daha mı iyi? Olmazsa, birini üst üste kullanmanın nedenleri neler olabilir?


1
Neden profil oluşturmuyorsun ve geri kalanımız bize sonucu bildirdi? Genel olarak konuşursak, performans stil tercihinden daha ağır basar.
Demian Brecht

3
"şimdiye kadar denediğim her DBMS'de aynı sorgu planlarına neden oldu" Bu, performans açısından bir cevaba sahip olabilseydi, stackoverflow.com'da bunu isterdi. ne yazık ki, onlar aynı sorgu.
SingleNegationElimination

Ah .. Kaçırdım :)
Demian Brecht

2
"Öznel", "senin fikrin ne" anlamına gelmez. Ben kaydetmiştiniz tür ortaya koydu kriterler buluştuğu SSS .
Aaron,

Sürprizi en aza indirmek için de bu stile yöneliyorum, sanırım kendi sorunuzu cevapladınız. Sürprizler kötüdür.
Pieter B,

Yanıtlar:


60

İkinci formun daha iyi olduğunu buldum. Öyle olabilir, çünkü onu böyle öğrendim, itiraf edeceğim, ancak kaygılarımdan birinin somut bir sebebi var - endişelerin ayrılması. Yan tümce tablolarda katılmak için kullandığınız alanları koymak sorguları anlamakta zorluklara yol açabilir.

Örneğin, aşağıdaki sorguyu alın:

select *
from table1, table2, table3, table4
where table1.id = table2.id
and table2.id = table3.id
and table3.id = table4.id
and table1.column1 = 'Value 1'

Yukarıdaki sorgu, tablo birleştirme koşullarına ve gerçek iş mantığı koşullarının tümü tek bir boşlukta birleştirilmiştir. Büyük bir sorgu ile bunu anlamak çok zor olabilir.

Ancak şimdi bu kodu alın:

select *
from table1 join table2 on table1.id = table2.id
join table3 on table2.id = table3.id
join table4 on table3.id = table4.id
where table1.column1 = 'Value 1'

Bu durumda, tablolarla veya bunların ilişkileriyle ilgili yapılması gerekenlerin tümü, cümlecikten izole edilmiştir, sorgu kısıtlaması için gerçek iş mantığı, cümlededir. Özellikle daha büyük sorgular için bunun çok daha anlaşılabilir olduğunu düşünüyorum.


Bu, özellikle iki masayı geçtiğinizde veya sol, sağ ve tam birleşimlerin bir kombinasyonuna ihtiyaç duyduğunuzda bunu yapmanın tek mantıklı yoludur.
aglassman

5
+1 "Endişelerin ayrılması" için bir araya

39

Join sözdizimi, 1992'de eski virgül sözdiziminin yerine geçmiştir. Halen, virgül sözdizimi ile kod yazmak için hiçbir neden yoktur. Hiçbir şey kazanmazsınız ve açık sözdiziminde sahip olmadığınız bazı sorunlara maruz kalırsınız.

İlk etapta daha karmaşık sorgular alırken, nerede bir durumu kaçırmak suretiyle kazara çapraz birleştirme yapmak çok kolaydır. Bu açık birleştirme sözdiziminin, sözdizimi hatası alacağınız için olmasını engelleyebileceği bir şeydir.

Bir çapraz birleştirme niyetindeyseniz, açık birleştirme sözdizimi, örtülü sözdiziminde, bakım yapan bir kişinin nerede cümle eklemeyi unuttuğunuzu varsayabileceğini açıkça belirtir.

Daha sonra örtük sözdizimini kullanarak en azından bazı db'lerde sorunlu olan sol ve sağ birleşme problemi var. SQL Server'da kullanımdan kaldırılmışlardır ve aslında eski sürümlerde bile doğru sonuçlar vermezler. Dış birleşim gerektiren hiçbir sorgu, SQL Server'da örtük sözdizimini içermemelidir.

Dahası, burada ve insanlar açık ve net birleşimleri karıştırdığında yanlış sonuçların olduğu (örneğin bir sol birleştirme eklerken) soruları gördüm, bu yüzden bunları karıştırmak kötü bir fikir.

Sonunda örtük birleştirmeler kullanan birçok kişi aslında birleşmeleri anlamıyor. Bu, bir veritabanını etkili bir şekilde sorgulamanız gereken kritik bir anlayıştır.


Açıklama için teşekkür ederim. Bana öğretildiğinde ikisine de sözdizimi gösterildi, ancak fark açıklanmadı. Bazen eksik olan sorguları üretmeyi başardım, bu da açıkça açıkça katılımın üstünde yazanların miktarını artıracağı yerdi.
awiebe

8

Ha. PostgreSQL'in belgelerine bakarken, kendi soruma olası bir cevap buldum . Bu sayfanın ne açıkladığını özetlemek için, sonuçta ortaya çıkan sorgu hala aynıdır, ancak optimize edicinin göz önünde bulundurması gereken plan sayısı, birleşme sayısıyla birlikte katlanarak artar.

Bu tür yaklaşık altı birleşimden sonra, sayı o kadar büyüktür ki, sorguyu planlama süresi fark edilebilir ve yaklaşık ondan sonra, optimizer kapsamlı bir plan araştırmasından olasılıklı bir aramaya geçecektir ve en uygun plana ulaşamayacaktır .

Bir çalışma zamanı parametresi ayarlayarak, planlayıcıya açıkça belirtilen iç ve çapraz birleşimleri açıkça birleştirmelerden farklı şekilde tedavi etmesini, onları planın tepesine zorlamasını ve diğer seçenekleri keşfetmemesini söyleyebilirsiniz.

Not olarak, varsayılan davranış her iki durumda da aynıdır ve alternatif planlar almanın dbms'nin içindekileri ve söz konusu tabloların farklı bir sonuç alabilmesi için bilgi sahibi olmasını gerektirir.


2
Ancak bu dokümanları biraz yanlış anladınız. İlk olarak, aslında üç eşik var. Biri işaret ettiğiniz gibi GEQO'yu ateşler; diğer ikisi (çöküş sınırlarından gelen ve birleşen sınırlar), planlamacının birleştirme sırasını yeniden düzenlemek yerine uygulanabilir dizinleri seçmeye zorlamasını sağlar. İkincisi ve en önemlisi, sorgular ayrıştırıldığı gibi yeniden yazılır. Bu, örnek sorguların birincisinin, ikincisininkiyle aynı sorgu ağacında ayrıştırılmasıyla sonuçlanır - eşikler daha sonra PG'ye, birleşmeleri yeniden sipariş etmeli veya vermemesi gerektiğini bilmesini sağlar.
Denis de Bernardy

8

İşte burada küme teorisi görüntüsü:

İki (veya daha fazla) tablo adını ayırmak için virgül kullandığınızda, istediğiniz şey kartezyen ürünüdür. 'Sol' tablonun her satırı, sağ tablonunkiyle 'birleştirilir' (birleştirilir).

Şimdi nerede yan tümce bir şey yazarsanız, bu 'birleştirme' bir koşul koymak gibi hangi satırları hangi satırları 'birleştirmek' söyleyerek bir koşul koymak gibi.

Bu aslında satırları "birleştirmektir" ve dolayısıyla daha okunaklı bir sözdizimi sağlamaya yardımcı olan ve gerçekten de bazı ortak değerlere katılmak istediğinizden daha anlaşılabilir olan join anahtar kelimesidir. @Dustin yukarıda açıklığa kavuşturduğuna benzer.

Şimdi, her DBMS akıllıdır, yani ilk önce kartezyen ürünü hesaplamaz ve daha sonra verileri filtreler (aşırı israf), ancak bunu sorgu yapısına dayanarak yapar. Aklıma gelen tek şey, 'katılmak' istediğinde, katılım faaliyetini açık bir hale getirmek gibidir ve muhtemelen kodu daha hızlı çalıştırmaya yardım eder (ne kadar? Bunu profillemeli ve görmelisin) virgülle ayrılmış durumda, optimum stratejiyi bulmak için biraz zamana ihtiyaç vardır. Yanılıyor olabilirim ama nasıl kodlayacağına dair eğitimli bir tahmin yapıyorum.


5

JOIN ifadelerini kullanmak için genellikle daha iyi olduğunu düşünüyorum.

Gelecekte, bildirimin bir INNER JOIN'den bir OUTER JOIN'e değiştirilmesini gerektiren bir durum ortaya çıkarsa, ikinci ifade ile yapılması çok daha kolay olacaktır.


3

Herhangi bir RDBMS bunları yürütme açısından aynı hale getirecek. İnsanın daha okunaklı ve anlamlı olup olmadığı ortaya çıkıyor.

JOIN öğesini kullanın, böylece birleşim eşleşmesi ile gerçek seçimin ne olduğu açıktır:

select name, deptname
from people p, departments d
where p.deptid = d.id and p.is_temp = 'Y'

vs.

select name, deptname
from people p
    inner join departments d on p.deptid = d.id
where p.is_temp = 'Y'

İkinci durum, hangi birleşme koşulunun ve seçim kriterinin hangisi olduğunu hemen netleştirir.


1

Sadece bir kere iki sonucu farklı bir optimizasyon kümesinde görmüştüm ve eğer bellek işe yararsa, gerçekten kıllı bir sorguda ms-sql2k'deydi. Bu örnekte * = ile kullanılan eski form yaklaşık 4x daha hızlı performansla sonuçlandı. Hiç kimse, Microsoft teknoloji adamlarımız dahil, nedenini açıklayamadı. MS’ler bir hatayı etiketledi. Bir daha hiç görmedim.

RDBMS'lerin çoğu tam kartezyenleri yapmayacak kadar akıllı olduğundan, kullanmamayı düşünebilmemin en büyük nedeni (amortismana tabi tutulmasının yanı sıra) birlikte çalıştığım 30-35 yaş altındaki kişilerin çoğunun hiç görmemiş olmalarıdır. önce eski form ve karşılaştıklarında korkunç bir şekilde kayboluyorlar.


Tabii ki sol birleştirme sözdizimi hiçbir zaman güvenilir şekilde doğru sonuçlar vermedi (bkz. SQL Server 2000 için BOL), bu yüzden daha hızlı olsaydı bile, onu değiştirirdim.
HLGEM

Bununla hiç karşılaşmadım ve yıldızla arama yapmak asla iyi bitmiyor, bir örneğiniz var mı?
Bill

-1

Eski tarzın kullanımdan kaldırılmış olması, kullanmamalısın.

Hangisinin daha iyi veya daha iyi olduğu konusunda bir tartışma bile yapılmamalıdır. Yeni kod eski sözdizimini kullanmamalı.


Bence bu cevap, neden kullanımdan kaldırıldığını ve kullanılmaması gerektiğini söylemeden hiçbir şey eklemiyor.
RemcoGerlich

1
@RemcoGerlich neden itiraz edildiğini burada tartışmıyor. Burada tartışılan şey eski mi yoksa yeni sözdiziminin mi kullanılacağıdır. Birinin diğerinden daha iyi ya da iyi olup olmadığı tartışmalıdır: eski sözdizimini kullanmamalısınız. Neden soru başka tartışmadır. (biri 20 yıl önce
Pieter B

-4

Veciz sözdiziminin nedenlerinden biri de veciz daha fazla olmasıdır, bu nedenle rahatsanız daha kolay okunur. Ayrıntılı durumun COBOL'de aritmetik yazmaya benzer olduğunu düşünüyorum, örn.


Downvoters: Bu yanıtta aslında yanlış bir şey var mı, yoksa sadece "size karşı çıkıyorsunuz" ifadesi var mı?
Adam Libuša
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.