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>  

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.


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


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.


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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.