Apakah urutan bergabung dalam masalah SQL?

189

Mengabaikan kinerja, apakah saya akan mendapatkan hasil yang sama dari kueri A dan B di bawah ini? Bagaimana dengan C dan D?

-- A
select *
from   a left join b
           on <blahblah>
       left join c
           on <blahblan>


-- B
select *
from   a left join c
           on <blahblah>
       left join b
           on <blahblan>  

-- C
select *
from   a join b
           on <blahblah>
       join c
           on <blahblan>


-- D
select *
from   a join c
           on <blahblah>
       join b
           on <blahblan>  
Pelajar saja
sumber
11
Apa <blahblah>? apakah Anda bergabung dengan A ke B dan A ke C, atau Anda bergabung dengan A ke B dan B ke C?
beny23
2
Hai Beny, kode dalam pertanyaan saya adalah abstraksi. Saya tidak khawatir untuk bergabung dengan A ke B atau A ke C, saya hanya ingin tahu apakah sintaksis seperti itu akan memberikan hasil yang identik.
Baru belajar

Jawaban:

225

Untuk INNERbergabung, tidak, urutannya tidak masalah. Kueri akan mengembalikan hasil yang sama, selama Anda mengubah pilihan Anda dari SELECT *menjadi SELECT a.*, b.*, c.*.


Untuk ( LEFT, RIGHTatau FULL) OUTERbergabung, ya, urutannya penting - dan ( diperbarui ) jauh lebih rumit.

Pertama, sambungan luar tidak komutatif, jadi a LEFT JOIN btidak sama denganb LEFT JOIN a

Gabungan luar juga tidak asosiatif, jadi dalam contoh Anda yang melibatkan properti (komutatif dan asosiatif):

a LEFT JOIN b 
    ON b.ab_id = a.ab_id
  LEFT JOIN c
    ON c.ac_id = a.ac_id

setara dengan :

a LEFT JOIN c 
    ON c.ac_id = a.ac_id
  LEFT JOIN b
    ON b.ab_id = a.ab_id

tapi:

a LEFT JOIN b 
    ON  b.ab_id = a.ab_id
  LEFT JOIN c
    ON  c.ac_id = a.ac_id
    AND c.bc_id = b.bc_id

tidak setara dengan :

a LEFT JOIN c 
    ON  c.ac_id = a.ac_id
  LEFT JOIN b
    ON  b.ab_id = a.ab_id
    AND b.bc_id = c.bc_id

Contoh asosiatif lain (semoga lebih sederhana). Pikirkan ini sebagai (a LEFT JOIN b) LEFT JOIN c:

a LEFT JOIN b 
    ON b.ab_id = a.ab_id          -- AB condition
 LEFT JOIN c
    ON c.bc_id = b.bc_id          -- BC condition

Ini setara dengan a LEFT JOIN (b LEFT JOIN c):

a LEFT JOIN  
    b LEFT JOIN c
        ON c.bc_id = b.bc_id          -- BC condition
    ON b.ab_id = a.ab_id          -- AB condition

hanya karena kami memiliki ONkondisi "baik" . Keduanya ON b.ab_id = a.ab_iddan keduanya c.bc_id = b.bc_idadalah pemeriksaan kesetaraan dan tidak melibatkan NULLperbandingan.

Anda bahkan dapat memiliki kondisi dengan operator lain atau yang lebih kompleks seperti: ON a.x <= b.xatau ON a.x = 7atau ON a.x LIKE b.xdan ON (a.x, a.y) = (b.x, b.y)dan dua kueri masih akan setara.

Namun, jika salah satu dari ini terlibat IS NULLatau fungsi yang terkait dengan nol seperti COALESCE(), misalnya jika kondisinya b.ab_id IS NULL, maka dua kueri tidak akan setara.

ypercubeᵀᴹ
sumber
3
Lebih tepat mengatakan bahwa gabungan luar asosiatif asalkan tidak ada predikat yang dapat dipenuhi oleh baris di mana semua kolom dari satu tabel NULL, daripada mengatakan bahwa asosiatif asalkan predikat tidak melibatkan IS NULL atau 'fungsi yang terkait dengan nulls'. Orang dapat dengan mudah membayangkan predikat yang memenuhi deskripsi sebelumnya tetapi tidak yang terakhir, seperti a.somecol > 0 OR b.someothercol > 0; asosiatif dapat gagal untuk kondisi itu.
Mark Amery
Tapi ya, saya pikir secara teknis memang benar untuk mengatakan bahwa OUTER JOIN asosiatif asalkan predikatnya tidak memenuhi salah satu syarat yang saya jelaskan di sini: stackoverflow.com/questions/20022196/… (yang pertama juga merusak asosiatif untuk INNER BERGABUNG, tetapi merupakan pendekatan yang murah dan jelas untuk memecahkannya yang mungkin tidak layak disebutkan.) Ini juga layak menunjukkan bahwa jenis yang paling umum BERGABUNG - BERGABUNG dengan kunci asing - tidak memenuhi salah satu dari kondisi tersebut dan dengan demikian bagus dan asosiatif.
Mark Amery
1
@MarkAmery Terima kasih, saya mengalami kesulitan menyusun kalimat-kalimat saya pada titik itu (dan saya sudah mengangkat jawaban Anda;)
ypercubeᵀᴹ
ypercube saya punya INNER JOINdan berikut LEFT JOIN. Apakah ini berfungsi seperti itu, pertama permintaan akan Filtercatatan di pangkalan INNER JOINdan kemudian akan berlaku LEFT JOINuntuk Filteredcatatan?
Muhammad Babar
Faktanya, semua tipe gabungan bersifat asosiatif, seperti yang ditentukan oleh standar SQL dan menurut definisi matematika dari asosiatif, tetapi mereka tidak tampak asosiatif karena menata ulang tanda kurung memerlukan memindahkan ONklausa (yaitu "spesifikasi gabungan") ke lokasi baru . Ini hanya sintaks. Jika Anda menggunakan notasi aljabar relasional (di mana spesifikasi gabungan ditempatkan di bawah operator gabungan), maka asosiatif menjadi lebih jelas. Argumen Anda hanya menampilkan bahwa sambungan luar tidak komutatif , yang benar
Lukas Eder
4

untuk Bergabung reguler, tidak. TableA join TableBakan menghasilkan rencana eksekusi yang sama dengan TableB join TableA(jadi contoh C dan D Anda akan sama)

untuk bergabung kiri dan kanan itu. TableA left Join TableBberbeda dari TableB left Join TableA, TETAPI sama sajaTableB right Join TableA

Diego
sumber
4
Ini hanya membahas komutatif, tetapi contoh-contoh dalam pertanyaan menunjukkan bahwa si penanya tertarik pada asosiatif. alamat jawaban ypercube keduanya.
Mark Amery
2

Jika Anda mencoba bergabung dengan C pada bidang dari B sebelum bergabung dengan B, yaitu:

SELECT A.x, A.y, A.z FROM A 
   INNER JOIN C
       on B.x = C.x
   INNER JOIN b
       on A.x = B.x

permintaan Anda akan gagal, jadi dalam hal ini urutan penting.

Teo J.
sumber
Ya ini benar, jawaban yang benar harus diubah.
Nir Pengas
-2

Oracle optimizer memilih gabungan urutan tabel untuk inner join. Pengoptimal memilih urutan gabungan tabel hanya dalam klausa FROM sederhana. Anda dapat memeriksa dokumentasi oracle di situs web mereka. Dan untuk kiri, gabung kanan luar, jawaban yang paling banyak dipilih adalah benar. Pengoptimal memilih urutan gabungan optimal serta indeks optimal untuk setiap tabel. Pesanan gabungan dapat memengaruhi indeks mana yang merupakan pilihan terbaik. Pengoptimal dapat memilih indeks sebagai jalur akses untuk tabel jika itu adalah tabel dalam, tetapi tidak jika itu adalah tabel luar (dan tidak ada kualifikasi lebih lanjut).

Pengoptimal memilih urutan gabungan tabel hanya dalam klausa FROM sederhana. Sebagian besar gabungan yang menggunakan kata kunci JOIN diratakan menjadi gabungan sederhana, sehingga pengoptimal memilih urutan gabungannya.

Pengoptimal tidak memilih urutan gabungan untuk gabungan luar; menggunakan urutan yang ditentukan dalam pernyataan.

Saat memilih pesanan bergabung, pengoptimal memperhitungkan: Ukuran setiap tabel Indeks tersedia pada setiap tabel Apakah indeks pada tabel berguna dalam urutan bergabung tertentu Jumlah baris dan halaman yang akan dipindai untuk setiap tabel di setiap tabel bergabung dalam pesanan

Saumyojit Das
sumber