Saya adalah pengguna MySQL jadul dan selalu lebih disukai JOIN
daripada sub-kueri. Tetapi saat ini semua orang menggunakan sub-kueri, dan saya benci; Saya tidak tahu kenapa.
Saya tidak memiliki pengetahuan teoretis untuk menilai sendiri apakah ada perbedaan. Apakah sub-kueri sebagus a JOIN
dan karena itu tidak ada yang perlu dikhawatirkan?
Jawaban:
Diambil dari manual MySQL ( 13.2.10.11 Subqueries Penulisan Ulang sebagai Bergabung ):
Jadi subqueries bisa lebih lambat daripada
LEFT [OUTER] JOIN
, tapi menurut saya kekuatan mereka sedikit lebih mudah dibaca.sumber
Join
dansub query
memiliki sintaks yang berbeda, sehingga keterbacaan kita tidak dapat membandingkan, keduanya memiliki keterbacaan yang lebih tinggi selama Anda baik dalam sintaks SQL. Kinerja lebih penting.Sub-kueri adalah cara yang benar secara logis untuk menyelesaikan masalah dalam bentuk, "Dapatkan fakta dari A, tergantung pada fakta dari B". Dalam kasus seperti itu, lebih logis untuk memasukkan B dalam sub-kueri daripada melakukan join. Ini juga lebih aman, dalam arti praktis, karena Anda tidak perlu berhati-hati dalam mendapatkan duplikasi fakta dari A karena beberapa pertandingan melawan B.
Namun secara praktis, jawabannya biasanya turun ke kinerja. Beberapa pengoptimal menghisap lemon saat diberi gabungan vs sub-kueri, dan beberapa menghisap lemon dengan cara lain, dan ini adalah pengoptimal-spesifik, versi-DBMS-spesifik, dan khusus-kueri.
Secara historis, bergabung secara eksplisit biasanya menang, oleh karena itu kebijaksanaan yang ditetapkan yang bergabung lebih baik, tetapi optimis semakin baik setiap saat, dan jadi saya lebih suka menulis pertanyaan terlebih dahulu dengan cara yang masuk akal secara logis, dan kemudian merestrukturisasi jika kendala kinerja menuntut hal ini.
sumber
select custid from cust join bought using (custid) where price > 500
. Jika pelanggan membeli beberapa barang mahal, Anda akan mendapatkan dobel. Untuk memperbaiki iniselect custid from cust where exists (select * from bought where custid = cust.custid and price > 500)
,. Anda dapat menggunakannyaselect distinct …
sebagai gantinya, tetapi seringkali lebih banyak pekerjaan, baik untuk pengoptimal atau evaluator.Umumnya
JOIN
s lebih cepat daripada sub-kueri dan sangat jarang sub-kueri menjadi lebih cepat.Di
JOIN
RDBMS dapat membuat rencana eksekusi yang lebih baik untuk permintaan Anda dan dapat memprediksi data apa yang harus dimuat untuk diproses dan menghemat waktu, tidak seperti sub-query di mana ia akan menjalankan semua permintaan dan memuat semua data mereka untuk melakukan pemrosesan .Hal yang baik dalam sub-kueri adalah bahwa mereka lebih mudah dibaca daripada
JOIN
s: itu sebabnya kebanyakan orang SQL baru lebih menyukainya; itu adalah cara yang mudah; tetapi ketika datang ke kinerja, GABUNG lebih baik dalam banyak kasus meskipun mereka tidak sulit dibaca juga.sumber
select * from a where a.x = (select b.x form b where b.id = a.id)
sangat kecil dibandingkan dengan bergabung. Ini adalah masalah yang sangat spesifik, tetapi dalam beberapa kasus ini membawa Anda dari jam ke menit.Gunakan EXPLAIN untuk melihat bagaimana database Anda mengeksekusi kueri pada data Anda. Ada "itu tergantung" besar dalam jawaban ini ...
PostgreSQL dapat menulis ulang sebuah subquery untuk bergabung atau bergabung ke subquery ketika dianggap satu lebih cepat daripada yang lain. Itu semua tergantung pada data, indeks, korelasi, jumlah data, permintaan, dll.
sumber
Pada tahun 2010 saya akan bergabung dengan penulis pertanyaan ini dan akan sangat memilih
JOIN
, tetapi dengan lebih banyak pengalaman (terutama di MySQL) saya dapat menyatakan: Ya, subquery bisa lebih baik. Saya sudah membaca banyak jawaban di sini; beberapa subqueries lain lebih cepat, tetapi tidak memiliki penjelasan yang baik. Saya harap saya bisa memberikan jawaban terlambat ini:Pertama-tama, izinkan saya mengatakan yang paling penting: Ada berbagai bentuk sub-kueri
Dan pernyataan penting kedua: Ukuran itu penting
Jika Anda menggunakan sub-kueri, Anda harus mengetahui bagaimana DB-Server mengeksekusi sub-kueri. Terutama jika sub-kueri dievaluasi sekali atau untuk setiap baris! Di sisi lain, DB-Server modern mampu mengoptimalkan banyak hal. Dalam beberapa kasus, subquery membantu mengoptimalkan kueri, tetapi versi yang lebih baru dari DB-Server mungkin membuat optimisasi menjadi usang.
Sub-kueri di Bidang-Pilih
Perlu diketahui bahwa sub-kueri dijalankan untuk setiap baris yang dihasilkan dari
foo
.Hindari ini jika memungkinkan; mungkin secara drastis memperlambat permintaan Anda pada kumpulan data besar. Namun, jika sub-kueri tidak memiliki referensi untuk
foo
itu dapat dioptimalkan oleh DB-server sebagai konten statis dan dapat dievaluasi hanya sekali.Sub-pertanyaan dalam pernyataan Dimana
Jika Anda beruntung, DB mengoptimalkan ini secara internal menjadi
JOIN
. Jika tidak, kueri Anda akan menjadi sangat, sangat lambat pada kumpulan data besar karena akan mengeksekusi sub-kueri untuk setiap barisfoo
, bukan hanya hasil seperti pada tipe-pilih.Sub-pertanyaan dalam pernyataan Bergabung
Ini menarik. Kami menggabungkan
JOIN
dengan sub-permintaan. Dan di sini kita mendapatkan kekuatan sebenarnya dari sub-kueri. Bayangkan sebuah dataset dengan jutaan bariswilco
tetapi hanya sedikit yang berbedame
. Alih-alih bergabung dengan meja besar, kami memiliki meja sementara yang lebih kecil untuk bergabung. Ini dapat menghasilkan pertanyaan yang jauh lebih cepat tergantung pada ukuran basis data. Anda dapat memiliki efek yang sama denganCREATE TEMPORARY TABLE ...
danINSERT INTO ... SELECT ...
, yang mungkin memberikan keterbacaan yang lebih baik pada pertanyaan yang sangat kompleks (tetapi dapat mengunci dataset dalam tingkat isolasi baca berulang).Sub-kueri bersarang
Anda dapat membuat sub-kueri di berbagai tingkatan. Ini dapat membantu pada kumpulan data besar jika Anda harus mengelompokkan atau mengurutkan hasilnya. Biasanya DB-Server membuat tabel sementara untuk ini, tetapi kadang-kadang Anda tidak perlu menyortir seluruh tabel, hanya di resultset. Ini mungkin memberikan kinerja yang jauh lebih baik tergantung pada ukuran tabel.
Kesimpulan
Sub-kueri bukan pengganti untuk
JOIN
dan Anda tidak boleh menggunakannya seperti ini (walaupun mungkin). Menurut pendapat saya yang sederhana, penggunaan yang benar dari sub-permintaan adalah penggunaan sebagai pengganti cepatCREATE TEMPORARY TABLE ...
. Sub-kueri yang baik mengurangi dataset dengan cara yang tidak dapat Anda capai dalamON
pernyataan aJOIN
. Jika sub-kueri memiliki salah satu kata kunciGROUP BY
atauDISTINCT
dan lebih disukai tidak terletak di bidang pilih atau pernyataan di mana, maka mungkin banyak meningkatkan kinerja.sumber
Sub-queries in the Join-statement
: (1) menghasilkan tabel turunan dari sub-kueri itu sendiri bisa memakan waktu yang sangat lama. (2) tabel turunan yang dihasilkan tidak diindeks. keduanya sendiri secara signifikan dapat memperlambat SQL.10
catatan, karena tidak ada indeks, itu masih berarti berpotensi untuk meminta 9 kali lebih banyak catatan data daripada dengan tabel temp saat Gabung tabel lainnya. BTW Saya punya masalah ini sebelumnya dengan db (MySQL) saya, dalam kasus saya, menggunakan sub-query diSELECT list
bisa jauh lebih cepat.EXPLAIN
kueri sebelum mengoptimalkan. Dengan yang lamaset profiling=1
Anda bisa dengan mudah melihat, jika meja sementara adalah hambatan. Dan bahkan indeks membutuhkan waktu pemrosesan, B-Trees mengoptimalkan permintaan untuk catatan, tetapi tabel catatan 10 bisa jauh lebih cepat daripada indeks untuk jutaan catatan. Tetapi itu tergantung pada banyak faktor seperti ukuran dan jenis bidang.Pertama-tama, untuk membandingkan keduanya terlebih dahulu Anda harus membedakan kueri dengan subkueri dengan:
Untuk kueri kelas pertama, RDBMS yang baik akan melihat gabungan dan subkueri sebagai setara dan akan menghasilkan rencana kueri yang sama.
Sekarang ini bahkan mysql melakukan itu.
Meski demikian, terkadang tidak, tetapi ini tidak berarti bahwa bergabung akan selalu menang - Saya memiliki kasus ketika menggunakan subquery di mysql meningkatkan kinerja. (Misalnya jika ada sesuatu yang mencegah perencana mysql untuk memperkirakan biaya dengan benar dan jika perencana tidak melihat varian gabungan dan varian subquery sama, maka subquery dapat mengungguli gabungan dengan memaksa jalur tertentu).
Kesimpulannya adalah Anda harus menguji pertanyaan Anda untuk varian join dan subquery jika Anda ingin memastikan yang mana yang akan berkinerja lebih baik.
Untuk kelas kedua perbandingan tidak masuk akal karena kueri tersebut tidak dapat ditulis ulang menggunakan gabungan dan dalam kasus ini subquery adalah cara alami untuk melakukan tugas yang diperlukan dan Anda tidak boleh mendiskriminasikannya.
sumber
Saya pikir apa yang kurang ditekankan dalam jawaban yang dikutip adalah masalah duplikat dan hasil bermasalah yang mungkin timbul dari kasus (penggunaan) tertentu.
(Meskipun Marcelo Cantos menyebutkannya)
Saya akan mengutip contoh dari kursus Lagunita Stanford tentang SQL.
Meja Siswa
Terapkan Tabel
(aplikasi dibuat untuk universitas dan jurusan tertentu)
Mari kita coba menemukan skor IPK untuk siswa yang telah mendaftar ke
CS
jurusan (terlepas dari universitas)Menggunakan subquery:
Nilai rata-rata untuk rangkaian hasil ini adalah:
Menggunakan gabungan:
nilai rata-rata untuk hasil ini:
Jelas bahwa upaya kedua menghasilkan hasil yang menyesatkan dalam kasus penggunaan kami, mengingat bahwa itu menghitung duplikat untuk perhitungan nilai rata-rata. Juga jelas bahwa penggunaan
distinct
dengan pernyataan join-based tidak akan menghilangkan masalah, mengingat hal itu akan secara salah menjaga satu dari tiga kemunculan3.9
skor. Kasus yang benar adalah untuk menghitung DUA (2) kejadian dari3.9
skor mengingat bahwa kami benar-benar memiliki DUA (2) siswa dengan skor yang memenuhi kriteria permintaan kami.Tampaknya dalam beberapa kasus, sub-kueri adalah cara paling aman, selain masalah kinerja.
sumber
Dokumentasi MSDN untuk SQL Server mengatakan
jadi jika Anda membutuhkan sesuatu seperti
coba gunakan gabung saja. Dalam kasus lain, tidak ada bedanya.
Saya katakan: Membuat fungsi untuk subqueries menghilangkan masalah cluttter dan memungkinkan Anda untuk menerapkan logika tambahan ke subqueries. Jadi saya sarankan membuat fungsi untuk subquery bila memungkinkan.
Kekacauan dalam kode adalah masalah besar dan industri telah berusaha menghindarinya selama beberapa dekade.
sumber
NOT EXISTS
. ANOT EXISTS
menang atas aLEFT OUTER JOIN
karena berbagai alasan: dalm, keselamatan-gagal (dalam kasus kolom nulable) dan keterbacaan. sqlperformance.com/2012/12/t-sql-queries/left-anti-semi-joinJalankan pada basis data yang sangat besar dari CMS Mambo lama:
0 detik
~ 3 detik
EXPLAIN menunjukkan bahwa mereka memeriksa jumlah baris yang sama persis, tetapi satu membutuhkan waktu 3 detik dan yang satu mendekati instan. Pesan moral dalam cerita? Jika kinerja itu penting (kapan bukan?), Cobalah beberapa cara dan lihat mana yang tercepat.
Dan...
0 detik
Sekali lagi, hasil yang sama, jumlah baris yang sama diperiksa. Dugaan saya adalah DISTINCT mos_content.catid membutuhkan waktu lebih lama untuk mencari tahu daripada DISTINCT mos_categories.id.
sumber
id
dan tidak dinamai seperti itucatid
? Mencoba mengoptimalkan akses db saya, dan pembelajaran Anda dapat membantu.Sesuai pengamatan saya seperti dua kasus, jika sebuah tabel memiliki kurang dari 100.000 catatan maka gabungan akan bekerja dengan cepat.
Tetapi dalam kasus bahwa tabel memiliki lebih dari 100.000 catatan maka subquery adalah hasil terbaik.
Saya memiliki satu tabel yang memiliki 500.000 catatan yang saya buat di bawah permintaan dan hasilnya adalah seperti
sumber
Subquery umumnya digunakan untuk mengembalikan satu baris sebagai nilai atom, meskipun mereka dapat digunakan untuk membandingkan nilai terhadap beberapa baris dengan kata kunci IN. Mereka diizinkan pada hampir semua titik yang berarti dalam pernyataan SQL, termasuk daftar target, klausa WHERE, dan sebagainya. Sub-kueri sederhana dapat digunakan sebagai kondisi pencarian. Misalnya, di antara sepasang tabel:
Perhatikan bahwa menggunakan operator nilai normal pada hasil sub-permintaan mengharuskan hanya satu bidang yang harus dikembalikan. Jika Anda tertarik untuk memeriksa keberadaan satu nilai dalam satu set nilai lainnya, gunakan IN:
Ini jelas berbeda dengan mengatakan LEFT-JOIN di mana Anda hanya ingin bergabung dengan hal-hal dari tabel A dan B bahkan jika kondisi gabungan tidak menemukan catatan yang cocok di tabel B, dll.
Jika Anda hanya khawatir tentang kecepatan, Anda harus memeriksa dengan database Anda dan menulis kueri yang baik dan melihat apakah ada perbedaan kinerja yang signifikan.
sumber
Versi MySQL: 5.5.28-0ubuntu0.12.04.2-log
Saya juga mendapat kesan bahwa BERGABUNG selalu lebih baik daripada sub-kueri di MySQL, tetapi EXPLAIN adalah cara yang lebih baik untuk membuat penilaian. Berikut adalah contoh di mana sub kueri bekerja lebih baik daripada GABUNGAN.
Inilah pertanyaan saya dengan 3 sub-pertanyaan:
MENJELASKAN menunjukkan:
Permintaan yang sama dengan BERGABUNG adalah:
dan hasilnya adalah:
Perbandingan
rows
kolom memberi tahu perbedaan dan permintaan dengan BERGABUNG gunakanUsing temporary; Using filesort
.Tentu saja ketika saya menjalankan kedua query, yang pertama dilakukan dalam 0,02 detik, yang kedua tidak selesai bahkan setelah 1 menit, jadi EXPLAIN menjelaskan pertanyaan ini dengan benar.
Jika saya tidak memiliki INNER BERGABUNG di atas
list_tag
meja yaitu jika saya menghapusdari kueri pertama dan sesuai:
dari kueri kedua, lalu EXPLAIN mengembalikan jumlah baris yang sama untuk kedua kueri dan kedua kueri ini berjalan sama cepat.
sumber
Subquery memiliki kemampuan untuk menghitung fungsi agregasi dengan cepat. Misalnya, temukan harga minimal buku dan dapatkan semua buku yang dijual dengan harga ini. 1) Menggunakan Subqueries:
2) menggunakan GABUNGAN
sumber
GROUP BY
s dengan tabel berbeda: stackoverflow.com/questions/11415284/... Subqueries tampaknya lebih umum. Lihat juga orang MySQL: dev.mysql.com/doc/refman/5.7/en/optimizing-subqueries.html | dev.mysql.com/doc/refman/5.7/en/rewriting-subqueries.htmlBeberapa orang mengatakan "beberapa RDBMS dapat menulis ulang subquery untuk bergabung atau bergabung ke subquery ketika berpikir yang lebih cepat dari yang lain.", Tapi pernyataan ini berlaku untuk kasus sederhana, pasti tidak untuk pertanyaan rumit dengan subquery yang sebenarnya penyebab masalah dalam kinerja.
sumber
Perbedaannya hanya terlihat ketika tabel gabungan kedua memiliki lebih banyak data secara signifikan daripada tabel primer. Saya punya pengalaman seperti di bawah ini ...
Kami memiliki tabel pengguna seratus ribu entri dan data keanggotaan mereka (pertemanan) sekitar 3 ratus ribu entri. Itu adalah pernyataan bergabung untuk mengambil teman dan data mereka, tetapi dengan penundaan besar. Tapi itu berfungsi dengan baik di mana hanya ada sejumlah kecil data di tabel keanggotaan. Setelah kami mengubahnya untuk menggunakan sub-kueri itu berfungsi dengan baik.
Tetapi sementara itu permintaan gabungan bekerja dengan tabel lain yang memiliki lebih sedikit entri daripada tabel utama.
Jadi saya pikir pernyataan join dan sub query bekerja dengan baik dan itu tergantung pada data dan situasinya.
sumber
Saat ini, banyak dbs dapat mengoptimalkan subqueries dan join. Jadi, Anda hanya perlu memeriksa permintaan Anda menggunakan menjelaskan dan melihat mana yang lebih cepat. Jika tidak ada banyak perbedaan dalam kinerja, saya lebih suka menggunakan subquery karena mereka sederhana dan lebih mudah dimengerti.
sumber
Saya hanya berpikir tentang masalah yang sama, tetapi saya menggunakan subquery di bagian FROM. Saya perlu koneksi dan permintaan dari tabel besar, tabel "slave" memiliki 28 juta catatan tetapi hasilnya hanya 128 sehingga data besar menghasilkan sangat kecil! Saya menggunakan fungsi MAX () di atasnya.
Pertama saya menggunakan LEFT JOIN karena saya pikir itu adalah cara yang benar, mysql dapat mengoptimalkan dll. Kedua kalinya hanya untuk pengujian, saya menulis ulang untuk sub-pilih terhadap JOIN.
Runtime BERGABUNG KIRI: runtuh 1.12s SUB-SELECT: 0.06s
18 kali lebih cepat daripada memilih bergabung! Hanya di adv chokito. Subselect terlihat mengerikan tetapi hasilnya ...
sumber
Jika Anda ingin mempercepat kueri Anda menggunakan gabung:
Untuk "gabung dalam / gabung", Jangan gunakan di mana kondisi alih-alih gunakan dalam kondisi "ON". Misalnya:
Untuk "Gabung Kiri / Kanan", Jangan gunakan dalam kondisi "ON", karena jika Anda menggunakan gabung kiri / kanan itu akan mendapatkan semua baris untuk satu tabel. Jadi, Tidak ada gunanya menggunakannya di "Aktif". Jadi, Coba gunakan kondisi "Di mana"
sumber