SQL Bergabung Vs Subkueri SQL (Kinerja)?

110

Saya ingin tahu apakah saya memiliki kueri bergabung seperti ini -

Select E.Id,E.Name from Employee E join Dept D on E.DeptId=D.Id

dan subkueri seperti ini -

Select E.Id,E.Name from Employee Where DeptId in (Select Id from Dept)

Saat saya mempertimbangkan kinerja, manakah dari dua kueri yang akan lebih cepat dan mengapa ?

Juga adakah waktu ketika saya harus memilih salah satu daripada yang lain?

Maaf jika ini terlalu sepele dan ditanyakan sebelumnya tapi saya bingung. Juga, akan lebih bagus jika kalian bisa menyarankan saya alat yang harus saya gunakan untuk mengukur kinerja dua pertanyaan. Terima kasih banyak!

Vishal
sumber
5
@ Lucero, pertanyaan ini diberi tag sql-server-2008, di mana kiriman yang Anda sebutkan diberi tag MySql. Anda dapat menyimpulkan bahwa jawabannya akan sama. Pengoptimalan kinerja dilakukan secara berbeda pada dua RDBMS.
Francois Botha

Jawaban:

48

Saya akan MENGHARAPKAN kueri pertama menjadi lebih cepat, terutama karena Anda memiliki persamaan dan GABUNG eksplisit. Menurut pengalaman saya INadalah operator yang sangat lambat, karena SQL biasanya mengevaluasinya sebagai serangkaian WHEREklausa yang dipisahkan oleh "OR" ( WHERE x=Y OR x=Z OR...).

Seperti halnya SEMUA HAL SQL, jarak tempuh Anda mungkin berbeda. Kecepatan akan sangat bergantung pada indeks (apakah Anda memiliki indeks pada kedua kolom ID? Itu akan sangat membantu ...) antara lain.

Satu-satunya cara NYATA untuk mengetahui dengan kepastian 100% mana yang lebih cepat adalah dengan mengaktifkan pelacakan kinerja (Statistik IO sangat berguna) dan menjalankan keduanya. Pastikan untuk menghapus cache Anda di antara proses!

JNK
sumber
16
Saya sangat meragukan jawaban ini, karena sebagian besar DBMS, pasti SQL Server 2008 dan yang lebih baru, menerjemahkan subkueri ID tunggal (tidak berkorelasi, artinya: tidak mereferensikan beberapa kolom kueri luar) menjadi semi-join yang relatif cepat. Selain itu, seperti yang disebutkan sebelumnya dalam jawaban lain, gabungan pertama yang sebenarnya akan mengembalikan baris untuk SETIAP kejadian ID yang cocok di Dept - ini tidak membuat perbedaan untuk ID unik, tetapi akan memberi Anda banyak duplikat di tempat lain. Menyortirnya dengan DISTINCT atau GROUP BY akan menjadi beban kinerja yang berat lainnya. Periksa rencana eksekusi di SQL Server Management Studio!
Erik Hart
2
Klausa IN sebagai padanan OR berlaku untuk daftar parameter / nilai, tetapi tidak untuk subkueri, yang kebanyakan diperlakukan seperti gabungan.
Erik Hart
42

Saya yakin ini adalah pertanyaan "Tua tapi Emas". Jawabannya adalah, tergantung!". Pertunjukan adalah subjek yang sangat sensitif sehingga akan terlalu konyol untuk mengatakan: "Jangan pernah menggunakan subkueri, selalu bergabung". Di tautan berikut, Anda akan menemukan beberapa praktik terbaik dasar yang menurut saya sangat membantu:

Saya memiliki tabel dengan 50000 elemen, hasil yang saya cari adalah 739 elemen.

Pertanyaan saya pada awalnya adalah ini:

SELECT  p.id,
    p.fixedId,
    p.azienda_id,
    p.categoria_id,
    p.linea,
    p.tipo,
    p.nome
FROM prodotto p
WHERE p.azienda_id = 2699 AND p.anno = (
    SELECT MAX(p2.anno) 
    FROM prodotto p2 
    WHERE p2.fixedId = p.fixedId 
)

dan butuh waktu 7,9 detik untuk mengeksekusinya.

Permintaan saya akhirnya adalah ini:

SELECT  p.id,
    p.fixedId,
    p.azienda_id,
    p.categoria_id,
    p.linea,
    p.tipo,
    p.nome
FROM prodotto p
WHERE p.azienda_id = 2699 AND (p.fixedId, p.anno) IN
(
    SELECT p2.fixedId, MAX(p2.anno)
    FROM prodotto p2
    WHERE p.azienda_id = p2.azienda_id
    GROUP BY p2.fixedId
)

dan butuh 0,0256 detik

SQL bagus, bagus.

linuxatico.dll
sumber
3
Menarik, dapatkah Anda menjelaskan bagaimana menambahkan GROUP BY memperbaikinya?
karena
6
Tabel sementara yang dibuat oleh subquery lebih kecil. Oleh karena itu pelaksanaannya lebih cepat karena data yang harus diperiksa lebih sedikit.
Sirmyself
2
Saya pikir di kueri pertama Anda telah berbagi variabel antara kueri luar dan subkueri, jadi untuk setiap baris dalam kueri utama, subkueri dijalankan tetapi di kueri kedua subkueri hanya dijalankan satu kali dan cara ini meningkatkan kinerja.
Ali Faradjpour
1
Sql server dan MySql dan ... Sql (kecuali NoSql) sangat mirip dalam infrastruktur. Kami memiliki sejenis mesin pengoptimalan kueri di bawahnya yang mengubah klausa IN (...) untuk digabungkan (jika memungkinkan). Tetapi ketika Anda memiliki Grup dengan kolom yang diindeks dengan baik (berdasarkan kardinalitasnya) maka itu akan jauh lebih cepat. Jadi itu sangat tergantung pada situasinya.
Alix
10

Mulailah melihat rencana eksekusi untuk melihat perbedaan bagaimana SQl Server akan menafsirkannya. Anda juga dapat menggunakan Profiler untuk benar-benar menjalankan kueri beberapa kali dan mendapatkan perbedaannya.

Saya tidak akan berharap ini menjadi sangat berbeda, di mana Anda bisa mendapatkan keuntungan kinerja yang nyata dan besar dalam menggunakan gabungan daripada subkueri adalah ketika Anda menggunakan subkueri yang berkorelasi.

EXISTS sering kali lebih baik daripada salah satu dari keduanya dan ketika Anda berbicara left join di mana Anda ingin semua record tidak ada di tabel left join, maka NOT EXISTS sering kali merupakan pilihan yang jauh lebih baik.

HLGEM
sumber
9

Performa didasarkan pada jumlah data yang Anda jalankan pada ...

Jika kurang data sekitar 20k. JOIN bekerja lebih baik.

Jika datanya lebih seperti 100k + maka IN bekerja lebih baik.

Jika Anda tidak membutuhkan data dari tabel lain, IN bagus, Tapi selalu lebih baik untuk yang sudah ada.

Semua kriteria ini saya uji dan tabel memiliki indeks yang sesuai.

JP Emvia
sumber
4

Performanya harus sama; jauh lebih penting untuk menerapkan indeks dan pengelompokan yang benar pada tabel Anda (terdapat beberapa sumber daya yang bagus tentang topik itu).

(Diedit untuk mencerminkan pertanyaan yang diperbarui)

Lucero
sumber
4

Kedua kueri tersebut mungkin tidak setara secara semantik. Jika seorang karyawan bekerja untuk lebih dari satu departemen (mungkin di perusahaan tempat saya bekerja; memang, ini berarti tabel Anda tidak sepenuhnya dinormalisasi) maka kueri pertama akan mengembalikan baris duplikat sedangkan kueri kedua tidak. Untuk membuat kueri setara dalam kasus ini, DISTINCTkata kunci harus ditambahkan ke SELECTklausa, yang mungkin berdampak pada kinerja.

Perhatikan ada aturan praktis desain yang menyatakan tabel harus memodelkan entitas / kelas atau hubungan antara entitas / kelas tetapi tidak keduanya. Oleh karena itu, saya sarankan Anda membuat tabel ketiga, misalnya OrgChart, untuk memodelkan hubungan antara karyawan dan departemen.

onedaywhen
sumber
4

Saya tahu ini adalah posting lama, tetapi saya pikir ini adalah topik yang sangat penting, terutama saat ini di mana kami memiliki lebih dari 10 juta catatan dan berbicara tentang terabyte data.

Saya juga akan memberi bobot pada observasi berikut. Saya memiliki sekitar 45 juta catatan di tabel saya ([data]), dan sekitar 300 catatan di tabel [kucing] saya. Saya memiliki pengindeksan ekstensif untuk semua kueri yang akan saya bicarakan.

Pertimbangkan Contoh 1:

UPDATE d set category = c.categoryname
FROM [data] d
JOIN [cats] c on c.id = d.catid

versus Contoh 2:

UPDATE d set category = (SELECT TOP(1) c.categoryname FROM [cats] c where c.id = d.catid)
FROM [data] d

Contoh 1 membutuhkan waktu sekitar 23 menit untuk dijalankan. Contoh 2 membutuhkan waktu sekitar 5 menit.

Jadi saya akan menyimpulkan bahwa sub-query dalam kasus ini jauh lebih cepat. Tentu saja perlu diingat bahwa saya menggunakan drive SSD M.2 yang berkemampuan i / o @ 1GB / detik (itu byte bukan bit), jadi indeks saya juga sangat cepat. Jadi ini juga dapat memengaruhi kecepatan dalam keadaan Anda

Jika ini adalah pembersihan data satu kali, mungkin yang terbaik adalah membiarkannya berjalan dan menyelesaikannya. Saya menggunakan TOP (10000) dan melihat berapa lama dan mengalikannya dengan jumlah record sebelum saya mencapai permintaan besar.

Jika Anda mengoptimalkan database produksi, saya sangat menyarankan data pra-pemrosesan, yaitu gunakan pemicu atau perantara kerja untuk memperbarui catatan asinkron, sehingga akses waktu nyata mengambil data statis.

Arvin Amir
sumber
0

Anda dapat menggunakan Rencana Jelaskan untuk mendapatkan jawaban yang obyektif.

Untuk masalah Anda, filter Yang Ada mungkin akan bekerja paling cepat.

Snekse
sumber
2
"Filter yang Ada mungkin akan berkinerja paling cepat" - mungkin tidak, menurut saya, meskipun jawaban pasti akan memerlukan pengujian terhadap data aktual. Filter yang ada kemungkinan akan lebih cepat jika ada beberapa baris dengan nilai pencarian yang sama - jadi filter yang ada mungkin berjalan lebih cepat jika kueri memeriksa apakah karyawan lain telah direkam dari departemen yang sama, tetapi mungkin tidak saat mencari di departemen yang sama meja.
Apakah itu akan berjalan lebih lambat dalam skenario terakhir itu?
Snekse
Ini akan bergantung pada pengoptimal - dalam keadaan tertentu, mungkin, tetapi biasanya saya mengharapkan kinerja yang sangat mirip.