Bergabung secara eksplisit vs implisit SQL

399

Apakah ada perbedaan efisiensi dalam gabungan eksplisit eksplisit dan implisit? Sebagai contoh:

SELECT * FROM
table a INNER JOIN table b
ON a.id = b.id;

vs.

SELECT a.*, b.*
FROM table a, table b
WHERE a.id = b.id;
dmanxiii
sumber
11
Pertanyaan bagus. Saya ingin tahu mengapa gabung eksplisit digunakan sama sekali. Apakah tidak mungkin melakukan semua permintaan tanpa itu?
andrew
6
gunakan kata kunci EXPLAIN untuk mengetahui perbedaan tentang kedua pertanyaan .. gunakan BERGABUNG dan lihat perbedaannya .. Jika Anda mencoba dalam tabel lebih dari 100k catatan, Anda dapat melihat perbedaannya ...
Jeyanth Kumar
@danrew Pertanyaan saya sebenarnya apakah bergabung secara implisit adalah bentuk "retas" (seperti dalam "Permintaan yang melibatkan lebih dari satu tabel, tidak menggunakan gabungan? Itu peretasan, bukan?")
bobobobo
3
Mereka berbeda, bergabung secara implisit akan mengejutkan Anda sesekali ketika berhadapan dengan nilai nol; gunakan bergabung secara eksplisit dan hindari bug yang muncul ketika "tidak ada yang berubah!"
BlackTigerX
1
Tidak ada perbedaan. ,adalah CROSS JOINdengan looser mengikat & INNER JOINadalah CROSS JOINdengan ONseperti WHEREtetapi ketat mengikat. Yang penting untuk dieksekusi adalah bagaimana DBMS mengoptimalkan kueri.
philipxy

Jawaban:

132

Dari segi kinerja, keduanya persis sama (setidaknya dalam SQL Server).

PS: Perlu diketahui bahwa IMPLICIT OUTER JOINsintaks sudah ditinggalkan sejak SQL Server 2005. ( IMPLICIT INNER JOINSintaks yang digunakan dalam pertanyaan masih didukung)

Penghentian "Gaya Lama" GABUNG Sintaks: Hanya Hal Sebagian

lomaxx
sumber
4
@ lomaxx, hanya demi kejelasan, bisa Anda menentukan mana sintaks dari 2 dalam pertanyaan sudah ditinggalkan?
J Wynia
8
Bisakah Anda memberikan dokumentasi pendukung? Ini terdengar salah pada beberapa level.
NotMe
21
Bagaimana Anda mencela standar SQL?
David Crawshaw
7
@david Crenshaw, gabung implisit tidak lagi dalam standar dan belum 18 tahun.
HLGEM
11
Apa yang disebut "gabungan implisit" dari varietas 'dalam' atau 'silang' tetap ada dalam Standar. SQL Server mencabut sintaksis luar "gaya lama" yang bergabung (yaitu *=dan =*) yang belum pernah Standar.
onedaywhen
129

Secara pribadi saya lebih suka sintaks bergabung karena lebih jelas bahwa tabel bergabung dan bagaimana mereka bergabung. Coba bandingkan kueri SQL yang lebih besar di mana Anda memilih dari 8 tabel yang berbeda dan Anda memiliki banyak pemfilteran di mana. Dengan menggunakan sintaks bergabung Anda memisahkan bagian-bagian di mana tabel bergabung, ke bagian di mana Anda memfilter baris.

grom
sumber
4
Saya sepenuhnya setuju, tapi ini di luar topik. OP bertanya tentang efisiensi.
villasv
56

Pada MySQL 5.1.51, kedua kueri memiliki rencana eksekusi yang identik:

mysql> explain select * from table1 a inner join table2 b on a.pid = b.pid;
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref          | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
|  1 | SIMPLE      | b     | ALL  | PRIMARY       | NULL | NULL    | NULL         |  986 |       |
|  1 | SIMPLE      | a     | ref  | pid           | pid  | 4       | schema.b.pid |   70 |       |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
2 rows in set (0.02 sec)

mysql> explain select * from table1 a, table2 b where a.pid = b.pid;
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref          | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
|  1 | SIMPLE      | b     | ALL  | PRIMARY       | NULL | NULL    | NULL         |  986 |       |
|  1 | SIMPLE      | a     | ref  | pid           | pid  | 4       | schema.b.pid |   70 |       |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
2 rows in set (0.00 sec)

table1memiliki 166208 baris; table2memiliki sekitar 1000 baris.

Ini adalah kasus yang sangat sederhana; itu tidak berarti membuktikan bahwa optimizer kueri tidak akan bingung dan menghasilkan rencana yang berbeda dalam kasus yang lebih rumit.

Matt Fenwick
sumber
Ini harus menjadi jawaban yang diterima. Ini benar, rencananya sama (atau dekat dengan pernyataan yang lebih besar) tetapi jumlah catatan akan drastis, sehingga menyebabkan perbedaan kinerja.
SovietFrontier
37

Sintaks kedua memiliki kemungkinan gabungan silang yang tidak diinginkan: Anda bisa menambahkan tabel ke bagian FROM tanpa klausa WHERE yang sesuai. Ini dianggap berbahaya.

edosoft
sumber
Bagaimana jika nama tabel dalam klausa dari dihasilkan dari tabel yang digunakan dalam klausa di mana?
Jus12
Anda dapat melakukan join silang dengan sintaks JOIN eksplisit. ( stackoverflow.com/a/44438026/929164 ) Anda mungkin mengartikannya kurang ketat, sehingga lebih rentan terhadap kesalahan pengguna.
Daniel Dubovski
15

Jawaban pertama yang Anda berikan menggunakan apa yang dikenal sebagai ANSI bergabung dengan sintaks, yang lain valid dan akan bekerja di semua basis data relasional.

Saya setuju dengan grom bahwa Anda harus menggunakan sintaks bergabung ANSI. Seperti yang mereka katakan, alasan utamanya adalah kejelasan. Alih-alih memiliki klausa di mana dengan banyak predikat, beberapa di antaranya bergabung dengan tabel dan yang lain membatasi baris yang dikembalikan dengan sintaks gabungan ANSI, Anda membuatnya dengan jelas menyilaukan kondisi mana yang digunakan untuk bergabung dengan tabel Anda dan yang digunakan untuk membatasi hasil.

andy47
sumber
5

Dari segi kinerja, keduanya persis sama (setidaknya dalam SQL Server) tetapi perlu diketahui bahwa mereka mencela sintaks gabung ini dan tidak didukung oleh sql server2005 di luar kotak.

Saya pikir Anda memikirkan operator * = dan = * yang sudah usang vs. "outer join".

Saya baru saja menguji dua format yang diberikan, dan mereka bekerja dengan baik pada database SQL Server 2008. Dalam kasus saya, mereka menghasilkan rencana eksekusi yang sama, tetapi saya tidak dapat dengan yakin mengatakan bahwa ini akan selalu benar.

Joshdan
sumber
5

@ lomaxx: Hanya untuk memperjelas, saya cukup yakin bahwa kedua sintaks di atas didukung oleh SQL Serv 2005. Sintaks di bawah ini TIDAK didukung namun

select a.*, b.*  
from table a, table b  
where a.id *= b.id;

Secara khusus, gabungan luar (* =) tidak didukung.

Deadbug
sumber
2
Terus terang saya tidak akan menggunakannya bahkan dalam SQL Server 2000, sintaks * = sering memberikan jawaban yang salah. Terkadang ia mengartikan ini sebagai cross joins.
HLGEM
2

Pada beberapa basis data (terutama Oracle) urutan gabungan dapat membuat perbedaan besar untuk kinerja permintaan (jika ada lebih dari dua tabel). Pada satu aplikasi, kami memiliki dua urutan perbedaan besar dalam beberapa kasus. Menggunakan sintaks gabungan dalam memberi Anda kendali atas ini - jika Anda menggunakan sintaks petunjuk yang benar.

Anda tidak menentukan database mana yang Anda gunakan, tetapi probabilitas menyarankan SQL Server atau MySQL di mana tidak ada perbedaan nyata.

Leigh Caldwell
sumber
1
Leigh, Anda bisa menggunakan petunjuk di gabungan implisit juga.
SquareCog
1
Di Oracle, sangat jarang bagi pesanan gabungan untuk memengaruhi rencana eksekusi dengan cara yang bermakna. Lihat artikel ini oleh Jonathan Lewis untuk penjelasan.
Jon Heller
1

Seperti yang dinyatakan Leigh Caldwell, pengoptimal kueri dapat menghasilkan rencana kueri yang berbeda berdasarkan apa yang secara fungsional tampak seperti pernyataan SQL yang sama. Untuk membaca lebih lanjut tentang ini, lihat dua posting blog berikut: -

Satu posting dari Tim Oracle Optimizer

Posting lain dari blog "Data Terstruktur"

Saya harap Anda menemukan ini menarik.

Mike McAllister
sumber
Mike, perbedaan yang mereka bicarakan adalah bahwa Anda perlu memastikan bahwa jika Anda menentukan gabungan secara eksplisit, Anda menentukan kondisi gabungan untuk bergabung, bukan filter. Anda akan mencatat bahwa untuk kueri yang benar secara semantik, rencana exec adalah sama.
SquareCog
1

Dari segi kinerja, seharusnya tidak ada bedanya. Sintaks gabungan eksplisit tampaknya lebih bersih bagi saya karena secara jelas mendefinisikan hubungan antara tabel dalam klausa dari dan tidak mengacaukan klausa di mana.

David
sumber
0

Pada dasarnya, perbedaan antara keduanya adalah bahwa yang satu ditulis dengan cara yang lama, sementara yang lain ditulis dengan cara yang modern. Secara pribadi, saya lebih suka skrip modern menggunakan definisi dalam, kiri, luar, kanan karena mereka lebih jelas dan membuat kode lebih mudah dibaca.

Ketika berhadapan dengan inner joins, tidak ada perbedaan nyata dalam keterbacaan, namun, itu mungkin menjadi rumit ketika berhadapan dengan joins kiri dan kanan seperti pada metode yang lebih lama Anda akan mendapatkan sesuatu seperti ini:

SELECT * 
FROM table a, table b
WHERE a.id = b.id (+);

Di atas adalah cara lama bagaimana gabungan kiri ditulis sebagai lawan dari yang berikut:

SELECT * 
FROM table a 
LEFT JOIN table b ON a.id = b.id;

Seperti yang dapat Anda lihat secara visual, cara modern cara penulisan skrip membuat kueri lebih mudah dibaca. (Ngomong-ngomong, hal yang sama berlaku untuk gabungan kanan dan sedikit lebih rumit untuk gabungan luar).

Kembali ke pelat ketel, itu tidak membuat perbedaan ke kompiler SQL bagaimana kueri ditulis saat menangani mereka dengan cara yang sama. Saya telah melihat campuran keduanya di database Oracle yang telah membuat banyak orang menulis ke dalamnya, baik yang lebih tua maupun yang lebih muda. Sekali lagi, ini bermuara pada seberapa mudah dibaca skrip dan tim yang Anda kembangkan.

Michele La Ferla
sumber
-1

Dalam pengalaman saya, menggunakan sintaks cross-join-dengan-mana-klausa sering menghasilkan rencana eksekusi yang rusak otak, terutama jika Anda menggunakan produk Microsoft SQL. Cara SQL Server mencoba untuk memperkirakan jumlah baris tabel, misalnya, sangat mengerikan. Menggunakan sintaks gabungan dalam memberi Anda kontrol atas bagaimana kueri dieksekusi. Jadi dari sudut pandang praktis, mengingat sifat atavistik dari teknologi basis data saat ini, Anda harus mengikuti bagian dalam.

Sean
sumber
5
Apakah Anda punya bukti tentang ini? Karena jawaban yang diterima mengatakan sebaliknya.
cimmanon