Apakah ada perbedaan materi antara kueri yang bergabung dengan klausa WHERE, dan kueri menggunakan GABUNG yang sebenarnya?

32

Dalam Pelajari SQL dengan Cara Keras (latihan enam) , penulis menyajikan kueri berikut:

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";

dan kemudian mengatakan bahwa:

Sebenarnya ada cara lain untuk mendapatkan pertanyaan seperti ini untuk bekerja yang disebut "bergabung". Saya menghindari konsep-konsep itu untuk saat ini karena mereka sangat membingungkan. Tetap berpegang pada cara ini bergabung dengan tabel untuk saat ini dan abaikan orang yang mencoba memberi tahu [Anda] bahwa ini entah bagaimana lebih lambat atau "kelas rendah".

Benarkah? Mengapa atau mengapa tidak?

Robert Harvey
sumber
3
Saya rasa tidak ada, tetapi Anda dapat mencoba melakukan EXPLAIN untuk melihat apakah ada perbedaan dalam eksekusi query.
GrandmasterB
6
Saya ingin menunjukkan sinyal yang saling bertentangan dari sebuah karya dengan "Jalan yang Keras" dalam judul yang melewatkan konsep "karena mereka benar-benar membingungkan". Tapi mungkin konsep saya tentang "jalan yang sulit" seharusnya salah. Tetapi sekali lagi, mungkin tidak.
Mindwin
7
GABUNG dengan sangat baik mengangkut niat (bergabung dengan tabel) ini meninggalkan bagian WHERE untuk filter yang sebenarnya dan membuatnya sedikit lebih mudah dibaca. (selain banyak implikasi lain)
Th 00 mÄ
2
Anda sedang belajar SQL dengan Cara yang Sulit jika pembuatnya tidak mau repot untuk menulis gabungan sederhana! Seperti yang dikatakan ThomasS dengan menggunakan GABUNGAN, niat menjadi lebih jelas, dan klausa WHERE menjadi lebih sederhana. Juga menggunakan BERGABUNG lebih baik mengilustrasikan teori set yang mendukung SQL.
Daniel Hollinrake
1
Tidak yakin bagaimana perasaan saya tentang sesuatu yang dimaksudkan untuk mengajari Anda sesuatu sambil berkata, "Tapi, hei kita akan melewatkan konsep mendasar ini karena itu pisang craaazzzyyyy." Saya pikir saya akhirnya mencari sumber yang berbeda untuk belajar. Pada titik tertentu Anda harus melakukan gabungan luar dan gabungan dan harus tahu cara melakukannya.
Maurice Reeves

Jawaban:

23

Dengan pendekatan penulis, mengajar GABUNGAN LUAR akan jauh lebih sulit. Klausa ON di INNER JOIN tidak pernah mengejutkan saya seperti banyak hal lainnya. Mungkin karena saya tidak pernah belajar dengan cara lama. Saya ingin berpikir ada alasan kami menyingkirkannya dan itu bukan untuk menjadi sombong dan menyebut metode ini kelas rendah.

Memang benar dalam skenario yang sangat sempit yang telah dibuat penulis:

  • Entry level SQL yang menggunakan ON itu rumit
  • Hanya mempertimbangkan JOIN / INNER JOIN dan bukan OUTER JOINs
  • Coder terisolasi yang tidak harus membaca kode orang lain atau memiliki orang yang berpengalaman dengan penggunaan ON membaca / menggunakan kode mereka.
  • Tidak memerlukan kueri kompleks dengan banyak: tabel, jika, tetapi dan atau.

Sebagai bagian dari perkembangan pengajaran, saya pikir lebih mudah untuk memecahnya dan memiliki perkembangan alami:

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

Konsep bergabung dan memfilter tabel tidak benar-benar sama. Belajar sintaks yang benar sekarang akan memiliki lebih carry-over ketika Anda belajar Outer BERGABUNG kecuali penulis bermaksud pada pengajaran usang / hal-hal usang seperti: *= or =*.

JeffO
sumber
5
Alasan pernyataan GABUNG ditambahkan adalah karena tidak ada standar untuk mengekspresikan gabungan luar, sehingga masing-masing vendor database memiliki sintaks "khusus" (tidak kompatibel) sendiri untuk itu. IIRC Oracle memiliki *=atau =*menunjukkan gabungan luar kiri atau kanan, yang lain yang saya gunakan hanya mendukung sambungan luar kiri menggunakan |=operator.
TMN
1
@ TMN IIRC Oracle digunakan +=atau mungkin itu =+. Saya percaya *=adalah Transact-SQL (Sybase dan kemudian MS-SQL). Tetap saja, poin bagus.
David
1
Di mana mulai rumit (IMHO) adalah ketika Anda memiliki campuran gabungan dalam dan luar. Dalam situasi seperti itu, saya akui kadang-kadang saya kembali ke teknik "kelas rendah" dalam melakukan penggabungan dalam WHEREklausa. (Saya pernah mendengar ini disebut sebagai theta bergabung , tetapi saya tidak yakin apakah itu benar.)
David
Operator IIRC seperti "lebih besar dari" atau "sama dengan" kadang-kadang disebut sebagai "operator theta", tetapi pencarian google mengarah ke beberapa operasi dalam kalkulus.
Walter Mitty
12

Apakah lebih lambat tergantung pada Pengoptimal Kueri dan bagaimana merampingkan kueri (apa yang Anda tulis sebenarnya bukan apa yang dieksekusi). Namun, masalah besar dari kutipan ini adalah ia sepenuhnya mengabaikan fakta bahwa ada berbagai jenis sambungan yang beroperasi sepenuhnya berbeda. Sebagai contoh, apa yang dikatakan adalah (secara teoritis) benar untuk inner joins, tetapi tidak berlaku untuk outer joins( left joinsdan right joins).

Locke
sumber
9
+1 Untuk jenis gabungan lainnya. Sebagian besar bergabung saya adalah INNER JOINatau LEFT OUTER JOIN. Mereka tidak "sangat membingungkan." SQL bisa membingungkan, tetapi ini bukan contohnya.
mgw854
off topic tapi harus pernyataan itu berbeda jenis bergabung s atau jenis bergabung ?
user1451111
9

Penulis menyajikan kasus sederhana di mana sintaks lama atau baru dapat digunakan. Saya tidak setuju dengan pernyataannya bahwa bergabung sangat membingungkan, karena bergabung dengan tabel adalah konsep query SQL mendasar. Jadi, mungkin penulis harus meluangkan waktu sebelumnya dalam menjelaskan bagaimana GABUNGAN bekerja sebelum mengucapkan pernyataan pendapat serta melakukan beberapa contoh kueri tabel.

Orang harus menggunakan sintaks yang lebih baru. Argumen utama untuk ini adalah bahwa kueri Anda akan memiliki:

  • Pilih Kriteria
  • Gabung Kriteria
  • Kriteria Filter

Menggunakan gaya lama, kriteria join dan filter digabungkan yang dalam kasus yang lebih kompleks dapat menyebabkan kebingungan.

Selain itu, orang bisa mendapatkan produk Cartesian dengan melupakan kriteria bergabung dalam klausa filter:

 person_pet.person_id = person.id

menggunakan sintaks yang lebih lama.

Menggunakan sintaks yang lebih baru juga menentukan bagaimana join seharusnya terjadi yang penting pada apakah Anda menginginkan INNER, LEFT OUTER, dll. Sehingga lebih eksplisit dalam hal JOIN syntax yang IMHO meningkatkan keterbacaan bagi mereka yang tidak terbiasa dengan bergabung dengan tabel.

Jon Raynor
sumber
5

Seharusnya tidak ada, parser kueri harus menghasilkan representasi internal yang setara untuk kueri yang setara terlepas dari bagaimana mereka ditulis. Penulis hanya menggunakan sintaks pra-SQL-92, itulah sebabnya ia menyebutkannya mungkin dipandang sebagai "kuno" atau "kelas rendah". Secara internal, pengurai dan pengoptimal harus menghasilkan rencana kueri yang sama.

TMN
sumber
5

Saya belajar SQL dengan cara ini, termasuk *= sintaks untuk gabungan luar. Bagi saya, itu sangat intuitif karena semua hubungan diberi prioritas yang sama dan melakukan pekerjaan yang lebih baik untuk mengatur pertanyaan sebagai serangkaian pertanyaan: Apa yang Anda inginkan? Anda ingin dari mana? Yang mana yang kamu inginkan?

Dengan melakukan joinsintaksis, itu mengganggu proses berpikir menuju hubungan yang lebih kuat. Dan secara pribadi, saya menemukan kode yang jauh lebih mudah dibaca dengan tabel dan hubungan yang saling terkait.

Setidaknya dalam MSSQL, tidak ada perbedaan yang berarti dalam kinerja kueri, dengan asumsi Anda menggunakan pemesanan gabungan yang sama. Yang mengatakan, ada satu masalah , yang jelas besar dengan belajar (dan menggunakan) SQL dengan cara ini. Jika Anda lupa salah satu relasi Anda, Anda akan mendapatkan produk silang yang tidak terduga. Yang mana pada basis data ukuran apa pun yang tidak sepele sangat mahal (dan berbahaya bagi yang tidak memilih!). Jauh lebih sulit untuk melupakan hubungan ketika menggunakan joinsintaks style.

Telastyn
sumber
7
Ini adalah relasional database, sehingga para hubungan cukup penting untuk query. Saya pribadi merasa jauh lebih sulit untuk memahami kueri yang mencampur filter yang benar (foo.x = 5) dengan hubungan (foo.x = bar.x). Mesin dapat dengan mudah mengoptimalkan ini menjadi gabungan, tetapi manusia pada dasarnya harus mempertimbangkannya baris demi baris, yang bertentangan dengan set dan himpunan bagian.
Aaronaught
4

Ada dua aspek yang berbeda untuk dipertimbangkan: Kinerja dan Maintainability / Keterbacaan .

Kemampu-rawatan / Keterbacaan

Saya memilih kueri yang berbeda, karena ini adalah sesuatu yang menurut saya merupakan contoh yang lebih baik / lebih buruk daripada kueri asli yang Anda posting.

Apa yang terlihat lebih baik untuk Anda dan lebih mudah dibaca?

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';

Atau...

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';

Bagi saya pribadi, yang pertama cukup mudah dibaca. Anda melihat bahwa kami bergabung dengan tabel INNER JOIN, yang berarti bahwa kami menarik baris yang cocok dengan klausa bergabung berikutnya (yaitu "bergabung dengan Karyawan dengan Riwayat Karyawan di Sejarah BisnisEntityID dan sertakan baris itu").

Yang terakhir, koma tidak ada artinya bagi saya. Itu membuat saya bertanya-tanya apa yang Anda lakukan dengan semua WHEREpredikat klausa itu.

Yang pertama lebih banyak membaca seperti yang dipikirkan otak saya. Saya melihat SQL sepanjang hari setiap hari dan koma untuk bergabung. Yang membawa saya ke poin saya berikutnya ...

Sebenarnya ada cara lain untuk mendapatkan pertanyaan seperti ini untuk bekerja yang disebut "bergabung"

Mereka semua bergabung. Bahkan koma adalah bergabung. Fakta bahwa penulis tidak menyebut mereka bahwa memang kejatuhan mereka .... tidak jelas. Itu harus jelas. Anda bergabung dengan data relasional, apakah Anda menentukan JOINatau ,.

Performa

Ini pasti akan tergantung pada RDBMS. Saya hanya dapat berbicara atas nama Microsoft SQL Server. Dari segi kinerja, ini setara. Bagaimana Anda tahu? Tangkap rencana pasca-eksekusi dan lihat apa yang sebenarnya dilakukan SQL Server untuk masing-masing pernyataan ini:

masukkan deskripsi gambar di sini

Pada gambar di atas, saya menyoroti bahwa saya menggunakan kedua kueri seperti di atas, hanya berbeda dalam karakter eksplisit untuk bergabung ( JOINvs ,). SQL Server melakukan hal yang persis sama.

Ringkasan

Jangan gunakan koma. Gunakan JOINpernyataan eksplisit .

Thomas Stringer
sumber
Saya belajar INNER BERGABUNG jauh sebelum saya menyadari bahwa varian dengan klausa WHERE sama, dan kedua contoh Anda terlihat sangat mudah dibaca oleh saya. Yang dengan WHERE dan koma mungkin lebih mudah dibaca. Di mana itu jatuh, saya pikir, adalah dalam pertanyaan kompleks besar, bukan yang relatif sederhana ini.
Robert Harvey
Intinya adalah, menganggap bahwa variasi koma bukan gabungan relasional tidak benar sama sekali.
Thomas Stringer
Saya pikir Anda salah menafsirkan koma sebagai bergabung. Koma hanya memisahkan tabel; itu adalah kondisi WHERE yang membuat gabungan, bukan koma.
Robert Harvey
1
Saya bisa mengatakan bahwa tidak ada yang bergabung dengan klausa predikat. Saya pikir Anda salah menafsirkan konstruksi kueri relasional Anda. Sudahkah Anda mencoba koma bergabung tanpa klausa WHERE? Itu masih berfungsi. Ini bergabung kartesian. Menurut Anda, apa yang Anda peroleh dengan menggunakan koma? Tolong jangan katakan bahwa Anda mencoba untuk menyimpan karakter.
Thomas Stringer
1
Saya akan mengatakan yang pertama lebih baik karena niat Anda lebih jelas. Ada lebih sedikit ambiguitas.
Daniel Hollinrake
4

Tidak, itu tidak benar sama sekali. Penulis sedang mengatur pembacanya untuk kebingungan, dan mendorong pemrograman kargo-kultus yang menghindari perbedaan struktural yang sangat kuat antara sintaks standar dan varian yang lebih tua ini ia lebih suka. Secara khusus, klausa WHERE yang berantakan membuatnya lebih sulit untuk mencari tahu apa yang membuat kueri khusus.

Teladannya membimbing pembaca untuk menghasilkan peta mental dari maknanya yang memiliki banyak kekacauan.

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";

Secara kasar, di atas adalah:

Dapatkan ID hewan peliharaan, NAMA, AGE, dan MATI untuk semua hewan peliharaan, person_pet, dan orang-orang di mana ID hewan peliharaan cocok dengan pet_id seseorang_pet, dan person_id dari catatan itu terjadi untuk cocok dengan person_id dari seseorang yang FIRST_NAMEnya "Zed"

Dengan peta mental seperti itu, pembaca (yang menulis SQL dengan tangan karena alasan tertentu) dapat dengan mudah membuat kesalahan, mungkin dengan menghilangkan satu atau lebih tabel. Dan pembaca kode yang ditulis sedemikian rupa harus bekerja lebih keras, untuk mencari tahu apa yang coba dilakukan oleh penulis SQL. ("Harder" berada pada level membaca SQL dengan atau tanpa penyorotan sintaks, tetapi masih lebih besar dari perbedaan nol.)

Ada alasan mengapa BERGABUNG adalah umum, dan itu adalah canard klasik "pemisahan masalah". Secara khusus, untuk permintaan SQL ada alasan bagus untuk memisahkan bagaimana data disusun vs bagaimana data disaring.

Jika permintaan dituliskan pembersih, seperti

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";

Kemudian pembaca memiliki perbedaan yang lebih jelas antara komponen-komponen dari apa yang diminta. Filter khusus dari kueri ini dipisahkan dari bagaimana komponen-komponennya saling berhubungan satu sama lain, dan komponen-komponen yang diperlukan dari setiap relasi berada tepat di sebelah tempat mereka diperlukan.


Tentu saja, sistem basis data modern mana pun tidak akan melihat perbedaan yang berarti antara kedua gaya tersebut. Tetapi jika kinerja database adalah satu-satunya pertimbangan, query SQL tidak akan memiliki ruang putih atau kapitalisasi.

DougM
sumber
2
Karena saya sudah mendengar ini menahan diri beberapa kali sekarang, izinkan saya berperan sebagai advokat iblis. Learn X the Hard Way adalah tentang memiliki kedalaman teknis; siapa pun dengan pemahaman yang baik tentang SQL benar-benar harus tahu bahwa kedua pendekatan itu setara, dalam hal output yang mereka hasilkan.
Robert Harvey
1
Saya bisa melihat itu, tetapi penulis tidak hanya menyatakan bahwa mereka adalah pernyataan yang setara dengan server SQL yang layak; mereka menyatakan bahwa menggunakan GABUNG adalah "membingungkan", yang merupakan jalan turun yang menunggu kode kotor. ("Tidak, jangan gunakan LINQ, cukup tulis pernyataan FOR Anda dengan tangan." "Kompiler tidak peduli dengan apa yang saya sebut metode ini, jadi tidak ada alasan untuk tidak menyebutnya FN1")
DougM
3

Guy membuat kesalahan klasik. Dia berusaha mengajarkan konsep abstrak dengan implementasi spesifik. Segera setelah Anda melakukannya, Anda masuk ke dalam kekacauan semacam ini.

Seharusnya mengajarkan konsep dasar database terlebih dahulu, kemudian menunjukkan SQL sebagai salah satu cara menggambarkannya.

Gabung kiri dan kanan, bisa dibilang tidak terlalu penting. Outer Join, yah Anda bisa menggunakan sintaks yang lama *=dan =*.

Sekarang Anda bisa berpendapat bahwa sintaks lebih sederhana, tetapi hanya untuk pertanyaan sederhana. Segera setelah Anda mulai mencoba melakukan kueri yang kompleks dengan versi ini, Anda bisa mendapatkan kekacauan yang mengerikan. Sintaks "baru" tidak diperkenalkan sehingga Anda bisa melakukan kueri yang rumit, melainkan Anda melakukan kueri kompleks dengan cara yang dapat dibaca dan karenanya dapat dipertahankan.

Tony Hopkinson
sumber
3
"Belajar X Jalan yang Keras" adalah pendekatan pembelajaran yang berbeda. Anda menulis kode, dan kemudian memahaminya nanti.
Robert Harvey
7
@RobertHarvey Itu bukan pendekatan pembelajaran yang berbeda, ini pendekatan standar. Nanti hanya terjadi jika Anda masih di tempat ketika roda lepas. berurusan dengan terlalu banyak orang yang menulis SQL yang berpikir tabel adalah array sel persegi panjang untuk memiliki kepercayaan pada metode ini.
Tony Hopkinson
2

Contohnya setara dengan reformulasi sederhana dengan GABUNGAN batiniah. Perbedaannya hanya terletak pada kemungkinan tambahan yang memungkinkan sintaks GABUNG. Misalnya, Anda dapat menentukan urutan kolom kedua tabel yang terlibat diproses; lihat misalnya https://stackoverflow.com/a/1018825/259310 .

Kebijaksanaan yang diterima adalah, ketika ragu-ragu, untuk menulis pertanyaan Anda dengan cara yang membuatnya lebih mudah dibaca. Tetapi apakah formulasi GABUNG atau DIMANA lebih mudah dibaca tampaknya merupakan masalah preferensi pribadi, itulah sebabnya mengapa kedua bentuk ini begitu tersebar luas.

Kilian Foth
sumber
Jawaban yang bagus, meskipun apakah Anda menggunakan WHEREatau memasukkan klausa dalam JOINpernyataan itu sebenarnya dapat memiliki dampak kinerja tergantung pada Pengoptimal Permintaan Saya telah melihatnya terjadi lebih dari sekali.
Locke
Pengalaman saya dengan dampak kinerja adalah ini: gabungan implisit akan memungkinkan pengoptimal kueri lebih banyak opsi untuk mengoptimalkan kueri, yang mungkin tampak seperti hal yang baik, tetapi bisa menjadi masalah. Secara khusus, pengoptimal kueri dapat menyesuaikan kueri dalam satu cara dalam pengembangan dan lainnya dalam produksi. Pengoptimal mungkin tertipu dalam penyetelan yang mengurangi kinerja. Rekomendasi saya adalah menggunakan sintaks join eksplisit DAN mengkonfirmasikan bahwa join menggunakan kolom yang memiliki indeks sehingga kinerja dapat diprediksi.
Michael Potter
2

Ketika saya belajar SQL, INNER JOIN, LEFT JOIN, dll. Bentuk tidak ada. Seperti jawaban lain telah menyatakan, dialek-dialek SQL yang berbeda masing-masing telah menerapkan gabungan luar menggunakan sintaksis istimewa. Ini merusak portabilitas kode SQL. Menyatukan bahasa kembali membutuhkan beberapa perubahan, dan KIRI BERGABUNG, dll. Adalah apa yang mereka pilih.

Memang benar bahwa untuk setiap INNER JOIN, koma yang sama dengan kondisi join di klausa WHERE dapat ditulis. Butuh beberapa saat untuk bermigrasi dari menyukai bentuk lama ke lebih suka bentuk baru. Rupanya, penulis Learning SQL the Hard Way masih menganggap cara lama lebih mudah.

Apakah ada perbedaan? Ya ada. Yang pertama adalah bahwa INNER GABUNG dengan klausa ON mengungkapkan maksud penulis lebih jelas daripada gaya lama bergabung. Fakta bahwa klausa ON sebenarnya adalah kondisi gabungan dan bukan semacam pembatasan lainnya lebih jelas. Ini membuat kode yang menggunakan INNER JOIN lebih mudah dipelajari saat membaca daripada gaya lama. Ini penting ketika mempertahankan kode orang lain.

Perbedaan kedua adalah bahwa gaya baru membuatnya sedikit lebih mudah bagi pengoptimal permintaan untuk menemukan strategi yang menang. Ini adalah efek yang sangat kecil, tetapi ini nyata.

Perbedaan ketiga adalah ketika Anda belajar menggunakan INNER JOIN (atau sekadar JOIN), itu membuatnya lebih mudah untuk belajar LEFT JOIN, dll.

Selain itu tidak ada perbedaan materi sama sekali.

Walter Mitty
sumber
0

Itu tergantung jika Anda berpikir dalam hal set dan logika formal .....

Jika Anda melakukannya, maka tidak menggunakan kata kunci "bergabung" membuat kemajuan yang lebih sederhana dari logika formal ke SQL.

Tetapi jika seperti 99% orang, Anda tidak menikmati logika formal dalam gelar matematika Anda, maka kata kunci gabungan lebih mudah dipelajari. SQL digunakan untuk dipresentasikan di universitas sebagai cara anter untuk menuliskan pertanyaan logika formal ....

Ian
sumber