WHERE yan tümcelerinin birleştirdiği sorgular ile gerçek bir JOIN kullanan sorgular arasında maddi bir fark var mı?


32

Gelen bilgi SQL Hard Way (egzersiz altı) , yazar hediyeler aşağıdaki sorgu:

SELECT pet.id, pet.name, pet.age, pet.dead
    FROM pet, person_pet, person
    WHERE
    pet.id = person_pet.pet_id AND
    person_pet.person_id = person.id AND
    person.first_name = "Zed";

ve sonra şunu söylemeye devam ediyor:

Bu tür sorguları "birleştirme" denilen işe almanın başka yolları da var. Şimdilik bu kavramlardan kaçınıyorum, çünkü delice kafa karıştırıcı. Şimdilik masalara katılmanın bu yoluna bağlı kalın ve bunun bir şekilde daha yavaş veya "düşük sınıf" olduğunu söylemeye çalışan insanları yoksayın.

Bu doğru mu? Neden ya da neden olmasın?


3
Var olduğunu sanmıyorum, ancak sorgu uygulamasında herhangi bir fark olup olmadığını görmek için bir EXPLAIN yapmayı deneyebilirsiniz.
GrandmasterB

6
Bir çalışmanın çelişkili sinyallerini, “delice kafa karıştırıcı oldukları için” kavramı atlayarak “Zor Yol” ile işaret etmek istiyorum. Ama belki de sadece "zor yoldan" ne olması gerektiği konusundaki fikrim yanlıştır. Ama yine, belki de değil.
Mindwin

7
JOIN çok iyi bir şekilde taşınır (tabloları birleştirerek) bu, gerçek filtreler için WHERE bölümünü bırakır ve okunmasını biraz kolaylaştırır. (maaanın diğer sonuçları dışında)
Th 00 mÄ s

2
Yazar basit katılımları yazmak için canınızı sıkmazsa, SQL'yi Zor Yoldan öğreniyorsunuz! ThomasS’in JOIN’leri kullanarak söylediği gibi niyetler daha net hale getirildi ve WHERE cümleleri daha kolaylaştı. Ayrıca JOIN'leri kullanmak, SQL'i destekleyen küme teorisini daha iyi göstermektedir.
Daniel Hollinrake

1
'' Hey, bu temel konsepti atlayacağız çünkü bu craaazzzyyyy muz '' diyerek size bir şey öğretmeyi amaçlayan bir şey hakkında ne hissettiğime emin değilim. Sanırım sonunda öğrenmek için farklı bir kaynak aradım. Bir noktada dış birleştirmeler ve çapraz birleştirmeler yapmanız ve bunları nasıl yapacağınızı bilmeniz gerekir.
Maurice Reeves

Yanıtlar:


23

Yazarın yaklaşımı ile OUTER JOIN'lere öğretmek çok daha zor olacak. INNER JOIN’deki ON cümlesi bana bir sürü şey gibi akıl aldırmadı. Belki de eskisi gibi öğrenmedim. Ondan kurtulmamızın bir sebebi olduğunu düşünmek isterim ve kendini beğenmiş ve bu yönteme düşük sınıf dememek değildi.

Yazarın yarattığı çok dar senaryoda doğru:

  • ON kullanarak böyle bir SQL giriş seviyesi karmaşıktır
  • Sadece JOIN / INNER JOIN düşünün, OUTER JOIN değil
  • İzole kodlayıcı, başkalarının kodunu okumak zorunda olmayan veya ON kullanımıyla ilgili kodlarını okuma / kullanma tecrübesi olan hiç kimseye sahip olmayan izole kodlayıcı.
  • Çok sayıda karmaşık sorgulama gerektirmez: eğer öyleyse, fakat's ve veya.

Öğretimin ilerlemesinin bir parçası olarak, onu parçalamanın ve doğal bir ilerlemeye sahip olmanın daha kolay olduğunu düşünüyorum:

Select * from table
select this, something, that from table
select this from table where that = 'this'
select this from table join anothertable on this.id = that.thisid

Tabloları birleştirme ve filtreleme kavramları aynı değildir. Doğru sözdizimini öğrenmek artık yazar eski gibi / kullanımdan kaldırılan şeyleri öğretme niyetinde olmadığı sürece OUTER JOINS'i öğrendiğinizde daha fazla kazanacaktır *= or =*.


5
JOIN ifadesinin eklenmesinin nedeni, dış birleşmeleri ifade etmek için bir standart bulunmaması nedeniyle, her veritabanı satıcısının kendi için "özel" (uyumsuz) sözdizimine sahip olmasıydı. IIRC Oracle, sol veya sağ dış birleşimlere sahipti *=veya =*belirtiyordu, bir tane daha kullandım, bir |=operatör kullanarak yalnızca desteklenen sol dış birleşimler .
TMN

1
@TMN IIRC Oracle kullanılmış +=ya da belki öyleydi =+. *=Transact-SQL (Sybase ve daha sonra MS-SQL) olduğuna inanıyorum . Yine de iyi nokta.
David

1
Karmaşıklaşmaya başladığı yer (IMHO), iç ve dış birleşimlerinizin bir karışımına sahip olduğunuz zamandır. Bu tür bir durumda, zaman zaman yandaşlarımı WHEREmaddeye koyma "düşük sınıf" tekniğine geri döndüğümü itiraf edeceğim . (Bunun bir theta katılımı olarak adlandırıldığını duydum , ancak doğru olup olmadığından emin değilim.)
David

"Büyük" veya "e eşit" gibi IIRC operatörlerine bazen "theta operatörleri" denir, ancak bir google araması da matematikte bir işlem yapılmasına neden olur.
Walter Mitty

12

Daha yavaş olması Sorgu Optimize Edici'ye ve sorguyu nasıl düzene soktuğuna bağlıdır (yazdıklarınız aslında yürütülen şey değildir). Bununla birlikte, bu teklifle ilgili en büyük sorun, tamamen farklı çalışan farklı türden birleşim olduğu gerçeğini tamamen görmezden gelmesidir. Örneğin, söylenen şey (teorik olarak) doğrudur inner joins, ancak outer joins( left joinsve right joins) için de geçerli değildir .


9
+1 Diğer bağlantı tipleri için. Benim katılır çoğu ya vardır INNER JOINya LEFT OUTER JOIN. "Delice kafa karıştırıcı" değiller. SQL delice kafa karıştırıcı olabilir, ancak bu bir örnek değil.
mgw854

konu dışı ama deyimi farklı olmalı katılmak tipleri s veya katılmak türlerini ?
user1451111,

9

Yazar, eski veya yeni sözdiziminin kullanılabileceği basit bir durum sunar. Birleşmelerin delice kafa karıştırıcı olduğu iddiasına katılıyorum, çünkü tablolara katılmak temel bir SQL sorgusu kavramıdır. Öyleyse, belki de yazar, JOINS'in bir görüşlü ifade vermeden önce ve birden fazla tablo sorgusu örneği yapmadan önce nasıl çalıştığını açıklamak için biraz zaman harcamış olmalıydı.

Bir daha yeni sözdizimi kullanmalıdır. Bunun ana argümanı, sorgunuzun sahip olacağıdır:

  • Kriterleri Seç
  • Kriterlere Katılın
  • Filtre Ölçütleri

Eski stil kullanılarak, daha karmaşık durumlarda karışıklığa yol açabilecek birleştirme ve filtre kriterleri birleştirilir.

Ayrıca, filtre yan tümcesinde birleştirme ölçütlerini unutarak Kartezyen ürün elde edilebilir:

 person_pet.person_id = person.id

eski sözdizimini kullanarak.

Daha yeni sözdiziminin kullanılması, bir INNER, LEFT OUTER, vb. İsteyip istemediğiniz konusunda önemli olan birleştirme işleminin nasıl gerçekleşmesi gerektiğini de belirtir, böylece IMHO'nun tablolara katılmayı bilmeyenler için okunabilirliği artıran JOIN sözdizimi açısından daha açıktır.


5

Olmaması gereken, sorgu çözümleyici nasıl yazıldığına bakılmaksızın eşdeğer sorgular için eşdeğer bir iç temsil oluşturmalıdır. Yazar sadece SQL-92 öncesi sözdizimini kullanıyor, bu yüzden "eski moda" veya "düşük sınıf" olarak görülebileceğini söylüyor. Dahili olarak, ayrıştırıcı ve optimize edici aynı sorgu planını oluşturmalıdır.


5

Ben de dahil olmak üzere SQL bu şekilde öğrendim *=Dış birleşimler sözdizimi . Bana göre, bütün ilişkilere eşit öncelik verildiği ve bir dizi soru olarak sorguları kurma konusunda daha iyi bir iş yaptığı için çok sezgiseldi: Ne istiyorsun? Onları nereden istiyorsun? Hangisini istiyorsun?

Yaparak joinSözdizimi , ilişkilere yönelik düşünce sürecini daha güçlü bir şekilde bozar. Ve şahsen, kodu tablolarla ve birbirleriyle iç içe geçmiş ilişkilerle daha az okunabilir buluyorum.

En azından MSSQL'de, aynı katılım siparişini kullandığınız varsayılarak, sorguların performansında anlamlı bir fark yoktur. Bununla birlikte , SQL'i bu şekilde öğrenme (ve kullanma) ile ilgili net ve büyük bir sorun var. İlişkilerinizden birini unutursanız, beklenmedik çapraz ürünler elde edersiniz. Hangi önemsiz olmayan herhangi bir boyutta bir veritabanında engelleyici pahalı (ve seçmeyenler için tehlikeli!). joinStil sözdizimini kullanırken bir ilişkiyi unutmak çok daha zor .


7
Bu bir var ilişkisel veritabanı, bu yüzden ilişkiler bir sorguya oldukça önemlidir. Kişisel olarak, gerçek filtreleri (foo.x = 5) ilişkilerle (foo.x = bar.x) birleştiren bir sorgunun anlamını zorlaştırır. Motor bunu kolayca bir birleştirme halinde optimize edebilir, ancak bir setin ve alt kümelerin aksine, temel olarak bir satır satır sebep olması gerekir.
Aaron,

4

Bunun dikkate alınması gereken iki farklı yönü vardır: Performans ve Bakım / Okunabilirlik .

İdame / Okunabilirlik

Farklı bir sorgu seçtim, sanırım gönderdiğiniz orijinal sorgudan daha iyi / daha kötü bir örnek.

Size daha iyi görünen ve daha okunaklı olan nedir?

select
    e.LoginID,
    DepartmentName = d.Name
from HumanResources.Employee e
inner join HumanResources.EmployeeDepartmentHistory edh
on e.BusinessEntityID = edh.BusinessEntityID
inner join HumanResources.Department d
on edh.DepartmentID = d.DepartmentID
where d.Name = 'Engineering';

Veya...

select
    e.LoginID,
    DepartmentName = d.Name
from HumanResources.Employee e, 
HumanResources.EmployeeDepartmentHistory edh,
HumanResources.Department d
where e.BusinessEntityID = edh.BusinessEntityID
and edh.DepartmentID = d.DepartmentID
and d.Name = 'Engineering';

Şahsen benim için, ilki oldukça okunaklı. Masalara katıldığımızı görüyorsunuzINNER JOIN anlamı bir sonraki yan tümce maddesine uyan satırları çektiğimizdir (yani, "BusinessEntityID'deki EmployeeDepartmentHistory ile Çalışan'a katıl ve bu satırları dahil et").

İkincisi, virgül benim için hiçbir şey ifade etmiyor. Tüm bunlarla ne yaptığını merak etmemi sağlıyor.WHERE şartların .

Eski beynimin düşündüğü gibi daha okur. Her gün SQL'e bakarım ve katılım için virgüller. Beni bir sonraki noktaya yönlendiren ...

Bu tür sorguları "birleştirme" denilen işe almanın başka yolları da var.

Hepsi birleşti. Virgüller bile bir birleşmedir. Yazarın onları aramadığı gerçeği aslında onların çöküşüdür .... belli değil. Açık olmalı. Belirlemiş olsanız da, ilişkisel verilere katılıyorsunuzdur JOINveya, .

performans

Bu kesinlikle RDBMS'ye bağımlı olacak. Sadece Microsoft SQL Server adına konuşabiliyorum. Performans açısından bunlar eşdeğerdir. Nereden biliyorsunuz? Yürütme sonrası planlarını yakalayın ve bu ifadelerin her biri için tam olarak SQL Server'ın ne yaptığını görün:

görüntü tanımını buraya girin

Yukarıdaki resimde, her iki sorguyu da yukarıda belirtildiği gibi kullandığımı, yalnızca birleştirme ( JOINvs ,) için açık karakterlerde farklı olduğumu vurguladım . SQL Server da aynı şeyi yapıyor.

özet

Virgül kullanmayın. Açık JOINifadeler kullanın .


INNER JOIN'leri, WHERE cümlelerinin varyantının eşdeğer olduğunu fark etmeden çok önce öğrendim ve her iki örneğiniz de bana çok okunaklı görünüyor. NEREDE ve virgüllerin olduğu daha okunaklı olabilir. Düştüğü yerde, göreceli olarak basit olanlardan değil, büyük karmaşık sorgular içinde olduğunu düşünüyorum.
Robert Harvey

Demek istediğim, virgül varyasyonunun ilişkisel birleşme olmadığını düşünmek doğru değildir.
Thomas Stringer

Bence virgülleri yanlış olarak yorumluyorsun. Virgüller yalnızca tabloları ayırır; virgül değil, birleşimi yaratan NEREDE koşulları.
Robert Harvey

1
Kesin şartlar cümlesinde hiçbir şekilde bir katılım olmadığını söyleyebilirim. Bence ilişkisel sorgunuzun yapısını yanlış yorumluyorsunuz. Virgülünüzü NEREDE cümleleri olmadan katılmayı denediniz mi? Hala çalışıyor. Kartezyen birleşme. Virgül kullanarak ne kazandığını düşünüyorsun? Lütfen karakterleri kaydetmeye çalıştığınızı söylemeyin.
Thomas Stringer

1
İlki daha iyi diyebilirim çünkü niyetleriniz daha net. Çok daha az belirsizlik var.
Daniel Hollinrake

4

Hayır, hiç doğru değil. Yazar, okurlarını karışıklık için hazırlıyor ve standart sözdizimi ile tercih ettiği daha eski değişkenler arasındaki çok güçlü bir yapısal farklılığı önleyen kargo-kült programlamasını teşvik ediyor. Özellikle, karışık bir WHERE deyimi sorgusunu özel kılan şeyin ne olduğunu bulmayı zorlaştırır.

Örneği, okuyucunun, çok fazla dağınıklığı olan, zihinsel bir haritasını çıkarmasına yol açar.

SELECT pet.id, pet.name, pet.age, pet.dead
    FROM pet, person_pet, person
    WHERE
    pet.id = person_pet.pet_id AND
    person_pet.person_id = person.id AND
    person.first_name = "Zed";

Kabaca, yukarıdaki:

Evcil hayvanın kimliği, NAME, AGE ve DEAD'in tüm evcil hayvanlar, person_pet ve evcil hayvan kimliğinin bir person_pet'in evcil hayvan kimliği ile eşleştiği ve bu kaydın kişi kimliği için FIRST_NAME "Zed" olan bir kişinin kimliği ile eşleşecek şekilde alın

Bunun gibi zihinsel bir harita ile, okuyucu (SQL'i bir nedenden dolayı elle yazan), muhtemelen bir veya daha fazla tabloyu atlayarak kolayca kolayca hata yapabilir. Ve bu şekilde yazılmış bir kod okuyucusu, SQL yazarının tam olarak ne yapmaya çalıştığını anlamak için daha çok çalışmak zorunda kalacaktır. ("Zor", sözdizimi vurgulaması olan veya olmayan SQL okuma düzeyindedir, ancak yine de sıfırdan büyük bir fark vardır.)

JOIN’lerin yaygın olmasının bir nedeni var ve bu eski klasik “kaygıların ayrılması” canavarı. Özellikle, bir SQL sorgusu için verinin nasıl yapılandırıldığını ve verilerin nasıl filtrelendiğini ayırmak için iyi bir neden vardır .

Sorgu temizleyici ise, örneğin

SELECT pet.id, pet.name, pet.age
FROM pet
  JOIN person_pet ON pet.id = person_pet.pet_id
  JOIN person ON person.id = person_pet.person_id
WHERE 
  person.first_name = "Zed";

O zaman okuyucu, istenen şeyin bileşenleri arasında daha net bir ayrım yapar. Bu sorgunun ayırt edici filtresi, bileşenlerinin birbirleriyle olan ilişkisinden ayrılır ve her bir ilişkinin gerekli bileşenleri, doğrudan gerekli oldukları yerin yanındadır.


Tabii ki, herhangi bir modern veritabanı sistemi, iki stil arasında anlamlı bir fark görmemelidir. Ancak, veritabanı performansı tek düşünce olsaydı, SQL sorgusu da beyaz boşluk ya da büyük harf kullanmazdı.


2
Bunun birkaç kez kaçındığını duyduğumdan beri, şeytanın avukatını oynamama izin verin. X Zor Yolunun teknik derinliğe sahip olduğunu öğrenin; İyi bir SQL anlayışı olan herkes , iki yaklaşımın ürettikleri çıktı bakımından eşdeğer olduğunu bilmelidir .
Robert Harvey,

1
Bunu görebiliyorum, ancak yazar, iyi bir SQL sunucusuna eşdeğer ifadeler olduklarını iddia etmiyor; JOIN kullanmanın “kafa karıştırıcı” olduğunu, kirli kodun bekleyeceği bir yol olduğunu iddia ediyorlar. ("Hayır, LINQ kullanmayın, FOR
ifadenizi

3

Adam klasik bir hata yapıyor. Özel bir uygulama ile soyut bir kavram öğretmeye çalışıyor. Bunu yapar yapmaz bu karmaşaya girersin.

Önce temel veritabanı kavramlarını öğretmeli, ardından SQL'i tanımlamanın bir yolu olarak göstermeliydim.

Sol ve sağ birleşimler çok fazla önemli olmadıkları söylenebilir. Dış Katılma, eski *=ve =*sözdizimini kullanabilirsiniz.

Şimdi sentaksın daha basit olduğunu iddia edebilirsin, ama sadece basit sorgular için. Bu sürümle karmaşık bir sorgu yapmaya başlar başlamaz korkunç bir karmaşaya kapılabilirsin. "Yeni" sözdizimi kullanılmadı, böylece karmaşık sorgular yapabilirdiniz, bu yüzden karmaşık sorgular okunabilir ve bu nedenle de bakımı kolay bir şekilde yapıldı.


3
"Zor Yolu X Öğrenin" farklı bir öğrenme yaklaşımıdır. Kodu yazıp daha sonra anlarsınız.
Robert Harvey,

7
@RobertHarvey Bu farklı bir öğrenme yaklaşımı değil, standarttır. Daha sonra sadece tekerlekler patladığında hala yerinde olursanız olur. bir tablonun, bu yönteme herhangi bir güven duyması için dikdörtgen hücre dizisi olduğunu düşünen çok sayıda insan SQL ile uğraşır.
Tony Hopkinson

2

Örnek, iç JOIN'lerle yapılan basit reformülasyonla eşdeğerdir. Fark, yalnızca JOIN sözdiziminin izin verdiği ek olasılıklarda yatmaktadır. Örneğin, söz konusu iki tablonun sütunlarının işlenme sırasını belirleyebilirsiniz; bkz. örneğin https://stackoverflow.com/a/1018825/259310 .

Alınan bilgelik, şüpheniz olduğunda, sorgularınızı daha okunaklı hale getirecek şekilde yazmaktır. Ancak JOIN veya NEREDE formülasyonların okunmasının daha kolay olup olmadığı kişisel tercih meselesi gibi görünmektedir, bu yüzden her iki form da bu kadar yaygındır.


İyi cevap, WHEREcümlede belirtilen ya da maddeyi kullansanız da JOIN, Sorgu Optimize Edici'ye bağlı olarak performans etkisi olabilir. Bunun bir kereden fazla olduğunu gördüm.
Locke

Performans etkisi konusundaki deneyimim şudur: örtülü katılımlar, sorgu optimizerine sorguyu optimize etmek için daha fazla seçenek sunacaktır; bu iyi bir şey gibi görünebilir, ancak sorun olabilir. Özellikle, sorgu iyileştirici sorguyu geliştirme aşamasında bir diğerini üretimde ayarlayabilir. Optimize edici, performansı düşüren ayarlamaya kandırılabilir. Önerim, açık birleştirme sözdizimini kullanmak ve birleşimin, performansın tahmin edilebilir olduğu şekilde dizinleri olan sütunlar kullandığını doğrulamak.
Michael Potter,

2

SQL öğrendiğimde INNER JOIN, LEFT JOIN, vs. formları yoktu. Diğer cevapların daha önce de belirttiği gibi, farklı SQL lehçeleri, kendine özgü sözdizimi kullanarak dış birleşmeler gerçekleştirmiştir. Bu SQL kodu taşınabilirliği zarar gördü. Dili bir araya getirmek biraz değişiklik gerektiriyordu ve LEFT JOIN, vs.

Her INNER JOIN için, WHERE yan tümcesinde join koşulu ile eşdeğer bir virgül birleşiminin yazılabileceği doğrudur. Eski formu beğenmekten yeni formu tercih etmekten geçmem biraz zaman aldı. Görünüşe göre, Zor Yolu Öğrenme SQL yazarı hala eski yolun daha kolay olduğunu düşünüyor.

Herhangi bir fark var mı? Evet, var. Birincisi, ON cümlesi olan bir INNER JOIN’in, yazarın niyetini eski stil birleşmesinden daha net bir şekilde ortaya koymasıdır. ON fıkrasının aslında bir birleşme koşulu olduğu ve başka bir kısıtlama olmadığı gerçeği daha açıktır. Bu, INNER JOIN'i kullanan kodu, eski stilden okurken öğrenmeyi daha kolay hale getirir. Bu başkasının kodunu korurken önemlidir.

İkinci fark, yeni stilin sorgu optimizerinin kazanan stratejiyi keşfetmesini marjinal olarak kolaylaştırmasıdır. Bu çok küçük bir etki, ama gerçek.

Üçüncü fark, INNER JOIN (veya sadece düz JOIN) kullanmayı öğrendiğinizde, LEFT JOIN, vb. Öğrenmeyi kolaylaştırmasıdır.

Bunun dışında hiçbir maddi fark yoktur.


0

Kümeler ve biçimsel mantık açısından düşünmenize bağlı.

Bunu yaparsanız, "join" anahtar sözcüğünü kullanmamanız resmi mantıktan SQL'e daha basit bir ilerleme olmasını sağlar.

Ancak, insanların% 99'u gibi, matematik derecenizde resmi bir mantıktan hoşlanmıyorsanız, join anahtar kelimesi öğrenmesi kolay bir izindir. SQL üniversitede resmi mantık sorgularını yazmak için başka bir yöntem olarak sunulurdu ....

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.