Menggunakan kata kunci JOIN atau tidak

45

Kueri SQL berikut ini sama:

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

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

Dan tentu saja menghasilkan rencana permintaan yang sama pada setiap DBMS yang pernah saya coba.

Tetapi seringkali, saya membaca atau mendengar pendapat bahwa yang satu pasti lebih baik dari yang lain. Secara alami, klaim ini tidak pernah dibuktikan dengan penjelasan.

Di mana saya bekerja, versi kedua tampaknya disukai oleh mayoritas pengembang lainnya, jadi saya juga cenderung ke arah gaya itu untuk meminimalkan kejutan. Tetapi dalam hati saya, saya benar-benar memikirkan yang pertama (karena itulah awalnya saya mempelajarinya).

Apakah salah satu dari bentuk-bentuk ini secara obyektif lebih baik daripada yang lain? Jika tidak, apa yang menjadi alasan untuk menggunakan salah satunya?

SingleNegationElimination
sumber
1
Mengapa tidak memprofilinya dan membiarkan kita semua tahu hasilnya? Secara umum, kinerja jauh melebihi preferensi gaya.
Demian Brecht
3
"menghasilkan rencana permintaan yang sama pada setiap DBMS yang pernah saya coba" Jika ini bisa memiliki jawaban dalam hal kinerja, itu akan menanyakannya di stackoverflow.com. sayangnya, mereka adalah permintaan yang sama.
SingleNegationElimination
Ah .. Merindukan itu :)
Demian Brecht
2
"Subyektif" tidak berarti "apa pendapat Anda". Saya telah mengedit ini untuk jenis memenuhi kriteria diletakkan di FAQ .
Aaronaught
Saya juga cenderung ke arah gaya itu untuk meminimalkan kejutan. Saya pikir Anda baru saja menjawab pertanyaan Anda sendiri. Kejutan itu buruk.
Pieter B

Jawaban:

60

Saya menemukan bahwa bentuk kedua lebih baik. Itu mungkin karena itulah bagaimana saya mempelajarinya, saya akui, tetapi saya punya satu alasan konkret - pemisahan keprihatinan. Menempatkan bidang yang Anda gunakan untuk bergabung dengan tabel di tempat klausa dapat menyebabkan kesulitan dalam memahami kueri.

Misalnya, ambil kueri berikut:

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'

Kueri di atas memiliki kondisi penyatuan tabel dan kondisi logika bisnis aktual yang digabungkan menjadi satu ruang. Dengan kueri besar, ini bisa sangat sulit untuk dipahami.

Namun, sekarang ambil kode ini:

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'

Dalam hal ini, segala sesuatu yang berkaitan dengan tabel atau bagaimana mereka berhubungan semuanya diisolasi dari klausa dari, sedangkan logika bisnis sebenarnya untuk pembatasan kueri ada di klausa mana. Saya pikir itu jauh lebih dimengerti, terutama untuk pertanyaan yang lebih besar.

Dustin Wilhelmi
sumber
Ini adalah satu-satunya cara yang masuk akal untuk melakukannya terutama setelah Anda melewati dua tabel, atau membutuhkan kombinasi gabungan kiri, kanan, dan penuh.
Aglassman
5
+1 Untuk "pemisahan masalah" bergabung,
39

Sintaks gabungan menggantikan sintaks koma lama pada tahun 1992. Saat ini tidak ada alasan untuk pernah menulis kode dengan sintaks koma. Anda tidak mendapatkan apa-apa dan Anda mengalami beberapa masalah yang tidak Anda miliki dengan sintaks eksplisit.

Pertama-tama ketika Anda mendapatkan pertanyaan yang lebih rumit, sangat mudah untuk melakukan join silang secara tidak sengaja dengan melewatkan kondisi di mana. Ini adalah sesuatu yang bisa mencegah sintaks bergabung secara eksplisit karena Anda akan mendapatkan kesalahan sintaksis.

Jika Anda berniat bergabung dengan silang, sintaks bergabung secara eksplisit akan memperjelasnya sementara dalam sintaksis tersirat seseorang yang melakukan pemeliharaan mungkin menganggap Anda lupa menambahkan klausa di mana.

Lalu ada masalah gabungan kiri dan kanan yang bermasalah di setidaknya beberapa dbs menggunakan sintaksis implisit. Mereka tidak lagi digunakan dalam SQL Server dan pada kenyataannya tidak mengembalikan hasil yang benar bahkan di versi yang lebih lama. Tidak ada permintaan yang membutuhkan gabungan luar harus mengandung sintaksis implisit dalam SQL Server.

Lebih lanjut, saya telah melihat pertanyaan di sini dan di situs lain di mana hasil yang salah terjadi ketika orang mencampur gabungan implisit dan eksplisit (ketika menambahkan gabungan kiri misalnya), jadi ide yang buruk untuk mencampurnya.

Akhirnya banyak orang yang menggunakan gabungan implisit tidak benar-benar mengerti bergabung. Ini adalah pemahaman kritis yang harus Anda miliki untuk secara efektif meminta database.

HLGEM
sumber
Terima kasih atas penjelasannya. Ketika saya diajari kami ditunjukkan kedua sintaks, tetapi perbedaannya tidak dijelaskan. Saya kadang-kadang berhasil membuat pertanyaan dengan kehilangan di mana yang terus terang akan meningkatkan jumlah penulisan hanya secara eksplisit bergabung di tempat pertama.
awiebe
8

Ha. Saya kebetulan menemukan jawaban yang mungkin untuk pertanyaan saya sendiri, sambil melihat dokumentasi untuk PostgreSQL . Untuk meringkas apa yang dijelaskan halaman ini, kueri yang dihasilkan masih sama, tetapi jumlah paket yang harus dipertimbangkan oleh pengoptimal bertambah secara eksponensial dengan jumlah gabungan.

Setelah sekitar enam bergabung seperti itu, jumlahnya sangat besar sehingga waktu untuk merencanakan kueri dapat terlihat, dan setelah sekitar sepuluh, pengoptimal akan beralih dari pencarian lengkap rencana ke pencarian probabilistik, dan mungkin tidak sampai pada rencana optimal .

Dengan menetapkan parameter run-time, Anda dapat menginstruksikan perencana untuk memperlakukan gabungan dalam dan lintas yang disebutkan secara berbeda dari gabungan implisit, memaksanya ke bagian atas paket, dan tidak menjelajahi opsi lain.

Dari catatan, perilaku default adalah sama dalam kedua kasus, dan bahwa mendapatkan rencana alternatif membutuhkan pengetahuan internal dbms dan kekhasan tabel yang bersangkutan untuk mendapatkan hasil yang berbeda.

SingleNegationElimination
sumber
2
Namun, Anda sedikit salah memahami dokumen itu. Pertama, sebenarnya ada tiga ambang batas. Seseorang menembakkan GEQO seperti yang Anda tunjukkan; dua lainnya (dari dan bergabung dengan batas keruntuhan) akhirnya membuat planer tetap memilih indeks yang berlaku daripada mengatur ulang urutan bergabung. Kedua dan sama pentingnya, kueri ditulis ulang saat diuraikan. Ini menghasilkan yang pertama dari contoh kueri yang diuraikan ke dalam pohon kueri yang sama persis dengan yang kedua - ambang kemudian beri tahu PG apakah harus mencoba memesan ulang gabungan atau tidak.
Denis de Bernardy
8

Nah di sini adalah pandangan teori himpunan itu:

Saat Anda menggunakan koma untuk memisahkan dua (atau lebih) nama tabel yang Anda inginkan adalah produk kartesius. Setiap baris dari tabel 'kiri' akan 'cocok' (digabungkan) dengan yang ada di tabel kanan.

Sekarang jika Anda menulis sesuatu di mana klausa, itu seperti meletakkan suatu kondisi pada 'rangkaian' ini dengan memberi tahu baris mana yang akan 'digabungkan' dengan baris mana.

Ini sebenarnya "bergabung" dengan baris :) dan karenanya kata kunci bergabung yang membantu memberikan sintaksis yang lebih mudah dibaca dan lebih dimengerti bahwa Anda 'memang' ingin bergabung pada beberapa nilai umum. Mirip dengan apa yang @Dustin telah jelaskan di atas.

Sekarang, setiap DBMS cerdas yaitu, ia tidak menghitung produk kartesius terlebih dahulu dan kemudian menyaring data (sangat boros) tetapi melakukannya berdasarkan struktur permintaan. Satu-satunya hal yang dapat saya pikirkan adalah, ketika Anda memintanya untuk 'bergabung' itu seperti membuat aktivitas bergabung secara eksplisit dan mungkin membantu menjalankan kode lebih cepat (seberapa banyak? Anda harus membuat profil dan melihatnya) tetapi di kasus terpisah koma, perlu waktu untuk 'mengetahui' strategi optimal. Saya mungkin salah, tapi saya hanya membuat tebakan bagaimana orang akan kode itu ...

PhD
sumber
5

Saya pikir umumnya lebih baik menggunakan pernyataan GABUNG untuk kasus itu.

Jika, di masa depan, muncul situasi yang mengharuskan perubahan pernyataan dari INNER JOIN menjadi OUTER JOIN, ini akan jauh lebih mudah dilakukan dengan pernyataan kedua.

Britt Wescott
sumber
3

Setiap RDBMS akan membuat mereka menjadi hal yang sama dalam hal eksekusi. Itu tergantung pada apakah seseorang lebih mudah dibaca dan ekspresif.

Gunakan GABUNG sehingga jelas apa yang cocok dengan pencocokan dan apa itu pilihan sebenarnya, seperti pada:

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'

Kasus terakhir segera menjelaskan yang merupakan kondisi bergabung, dan yang merupakan kriteria seleksi.

Andy Lester
sumber
1

Saya hanya pernah melihat keduanya menghasilkan serangkaian optimisasi yang berbeda dan jika ingatannya dalam ms-sql2k pada kueri yang sangat berbulu. Dalam satu contoh itu bentuk lama yang digunakan dengan * = menghasilkan sekitar 4x kinerja lebih cepat. Tidak ada seorang pun, termasuk teknisi Microsoft kami yang bisa menjelaskan alasannya. Orang-orang MS menyebutnya kesalahan. Saya belum pernah melihatnya lagi.

Karena sebagian besar RDBMS cukup pintar untuk tidak melakukan kartesius penuh, alasan terbesar yang dapat saya pikirkan untuk tidak menggunakannya (selain itu disusutkan) adalah bahwa sebagian besar orang di bawah 30-35 yang telah bekerja sama dengan saya belum pernah melihat bentuk lama sebelum dan sangat tersesat ketika mereka menemukannya.

Tagihan
sumber
Tentu saja yang tersisa bergabung dengan sintaks tidak pernah memberikan hasil yang benar andal (lihat BOL untuk SQL Server 2000) jadi bahkan jika itu lebih cepat, saya akan menggantinya.
HLGEM
Saya tidak pernah menemukan itu, dan mencari dengan tanda bintang tidak pernah berakhir dengan baik, apakah Anda memiliki contoh?
Bill
-1

Gaya lama telah usang, Anda seharusnya tidak menggunakannya.

Seharusnya tidak ada argumen tentang mana yang lebih baik atau tidak. Kode baru tidak boleh menggunakan sintaks lama.

Pieter B
sumber
Saya pikir jawaban ini tidak benar-benar menambahkan apa pun tanpa mengatakan mengapa itu sudah usang dan tidak boleh digunakan.
RemcoGerlich
1
@RemcoGerlich mengapa sudah usang tidak dibahas di sini. Apa yang sedang dibahas di sini adalah apakah akan menggunakan sintaks lama atau baru. Apakah satu lebih baik dari yang lain atau tidak diperdebatkan: Anda tidak harus menggunakan sintaksis lama. Pertanyaan mengapa adalah diskusi lain. (yang telah diselesaikan 20 tahun lalu.)
Pieter B
-4

Salah satu alasan untuk sintaks yang lebih singkat adalah lebih sintaks, jadi jika Anda merasa nyaman dengan itu, lebih mudah dibaca. Saya pikir kasus verbose mirip dengan menuliskan aritmatika dalam COBOL, misalnya MULTIPLY A BY B PEMBERIAN C.

John Bickers
sumber
Downvoters: Apakah ada sesuatu yang salah secara faktual dalam respons ini, atau apakah mereka hanya "tidak setuju dengan Anda" downvotes?
Adam Libuša