Pertanyaan Menggunakan inner join DISTINCT dalam SQL


Saya memiliki tiga tabel, A, B, C, di mana A banyak untuk satu B, dan B banyak untuk satu C. Saya ingin daftar semua C dalam A.

Tabel saya adalah sesuatu seperti ini: A [id, valueA, lookupB], B [id, valueB, lookupC], C [id, valueC]. Saya telah menulis permintaan dengan dua SELECT bersarang, tapi saya bertanya-tanya apakah mungkin untuk melakukan INNER JOIN dengan DISTINCT entah bagaimana.

SELECT valueC
FROM C
INNER JOIN
(
    SELECT DISTINCT lookupC
    FROM B INNER JOIN
    (
        SELECT DISTINCT lookupB
        FROM A
    ) 
    A2 ON B.id = A2.lookupB
) 
B2 ON C.id = B2.lookupC

EDIT: Tabel yang cukup besar, A adalah 500 ribu baris, B adalah 10 ribu baris dan C adalah 100 baris, jadi ada banyak info yang tidak perlu jika saya melakukan penggabungan bagian dalam dasar dan menggunakan DISTINCT pada akhirnya, seperti ini:

SELECT DISTINCT valueC
FROM 
C INNER JOIN B on C.id = B.lookupB
INNER JOIN A on B.id = A.lookupB

Ini sangat, sangat lambat (kali magnitudo lebih lambat daripada SELECT bersarang yang saya lakukan di atas.


32
2017-10-02 08:48


asal


Jawaban:


Saya melakukan tes pada MS SQL 2005 menggunakan tabel berikut: A 400K baris, B 26K baris dan C 450 baris.

Perkiraan rencana kueri menunjukkan bahwa gabungan dalam dasar akan menjadi 3 kali lebih lambat daripada sub-query bersarang, namun ketika benar-benar menjalankan kueri, gabungan dalam dasar dua kali lebih cepat daripada kueri yang bersarang, Penggabungan dalam dasar mengambil 297 ms pada sangat perangkat keras server minimal.

Database apa yang Anda gunakan, dan berapa kali Anda melihat? Saya berpikir jika Anda melihat kinerja yang buruk maka itu mungkin masalah indeks.


13
2017-10-02 13:38



Saya percaya Anda 1: m hubungan seharusnya sudah secara implisit menciptakan GABUNGAN DISTINCT.

Namun, jika sasaran Anda hanya C di masing-masing A, mungkin lebih mudah menggunakan DISTINCT di kueri paling luar.

SELECT DISTINCT a.valueA, c.valueC
FROM C
    INNER JOIN B ON B.lookupC = C.id
    INNER JOIN A ON A.lookupB = B.id
ORDER BY a.valueA, c.valueC

9
2017-10-02 08:55



SELECT DISTINCT C.valueC 
FROM C 
  LEFT JOIN B ON C.id = B.lookupC
  LEFT JOIN A ON B.id = A.lookupB
WHERE C.id IS NOT NULL

Saya tidak melihat alasan bagus mengapa Anda ingin membatasi kumpulan hasil A dan B karena apa yang ingin Anda miliki adalah daftar semua C yang direferensikan oleh A. Saya melakukan perbedaan pada C.valueC karena saya menebak Anda menginginkan daftar unik C.


EDIT: Saya setuju dengan argumen Anda. Bahkan jika solusi Anda terlihat sedikit bertumpuk, nampaknya ini adalah cara terbaik dan tercepat untuk menggunakan pengetahuan Anda tentang data dan mengurangi set hasil.

Tidak ada konstruksi gabung yang dapat Anda gunakan jadi tetaplah dengan apa yang sudah Anda miliki :)


2
2017-10-02 08:55



Apakah ini yang kamu maksud?

SELECT DISTINCT C.valueC
FROM 
C
INNER JOIN B ON C.id = B.lookupC
INNER JOIN A ON B.id = A.lookupB

0
2017-10-02 08:54