Saya refactored bagian lambat dari aplikasi yang kami warisi dari perusahaan lain untuk menggunakan gabungan dalam daripada subquery seperti:
WHERE id IN (SELECT id FROM ...)
Permintaan refactored berjalan sekitar 100x lebih cepat. (~ 50 detik hingga ~ 0,3) Saya mengharapkan peningkatan, tetapi adakah yang bisa menjelaskan mengapa itu sangat drastis? Kolom yang digunakan di mana klausa semuanya diindeks. Apakah SQL mengeksekusi query di mana klausa sekali per baris atau sesuatu?
Perbarui - Jelaskan hasil:
Perbedaannya ada di bagian kedua dari kueri "di mana id di ()" -
2 DEPENDENT SUBQUERY submission_tags ref st_tag_id st_tag_id 4 const 2966 Using where
vs 1 baris yang diindeks dengan gabungan:
SIMPLE s eq_ref PRIMARY PRIMARY 4 newsladder_production.st.submission_id 1 Using index
sql
mysql
performance
database-design
join
palmsey
sumber
sumber
Jawaban:
"Subquery berkorelasi" (yaitu, di mana kondisi tergantung pada nilai yang diperoleh dari baris kueri yang berisi) akan mengeksekusi satu kali untuk setiap baris. Subquery yang tidak berkorelasi (yang di mana kondisi independen dari kueri yang berisi) akan dieksekusi sekali di awal. Mesin SQL membuat perbedaan ini secara otomatis.
Tapi, ya, jelaskan-rencana akan memberi Anda rincian kotor.
sumber
DEPENDENT SUBQUERY
artinya sama persis dengan "subquery yang dikorelasikan".Anda menjalankan subquery satu kali untuk setiap baris sedangkan gabung terjadi pada indeks.
sumber
EXPLAIN
mengatakanDEPENDENT SUBQUERY
, yang merupakan indikator paling jelas dari perilaku ini.Berikut adalah contoh bagaimana sub-query dievaluasi dalam MySQL 6.0 .
Pengoptimal baru akan mengonversi subqueries semacam ini menjadi gabungan.
sumber
Jalankan menjelaskan-rencana pada setiap versi, itu akan memberi tahu Anda alasannya.
sumber
sebelum kueri dijalankan terhadap dataset yang dimasukkan melalui pengoptimal kueri, pengoptimal berupaya mengatur kueri sedemikian rupa sehingga dapat menghapus sebanyak tupel (baris) dari hasil yang ditetapkan secepat mungkin. Seringkali ketika Anda menggunakan subquery (terutama yang buruk) tupel tidak dapat dipangkas dari hasil yang ditetapkan sampai kueri luar mulai berjalan.
Tanpa melihat kueri, sulit untuk mengatakan apa yang begitu buruk tentang aslinya, tapi tebakan saya adalah sesuatu yang pengoptimal tidak bisa membuat lebih baik. Menjalankan 'jelaskan' akan menunjukkan kepada Anda metode pengoptimal untuk mengambil data.
sumber
Lihatlah paket permintaan untuk setiap permintaan.
Dimana dalam dan Bergabung dapat biasanya diimplementasikan dengan menggunakan rencana eksekusi yang sama, sehingga biasanya ada nol kecepatan-up dari mengubah antara mereka.
sumber
Pengoptimal tidak melakukan pekerjaan dengan sangat baik. Biasanya mereka dapat diubah tanpa perbedaan dan pengoptimal dapat melakukan ini.
sumber
Biasanya ini adalah hasil dari pengoptimal yang tidak dapat mengetahui bahwa subquery dapat dieksekusi sebagai gabungan dalam hal ini mengeksekusi subquery untuk setiap catatan dalam tabel daripada bergabung dengan tabel dalam subquery terhadap tabel yang Anda query. Beberapa basis data yang lebih "enterprisey" lebih baik dalam hal ini, tetapi terkadang mereka masih melewatkannya.
sumber
Pertanyaan ini agak umum, jadi inilah jawaban umum:
Pada dasarnya, permintaan memakan waktu lebih lama ketika MySQL memiliki banyak baris untuk disortir.
Melakukan hal ini:
Jalankan EXPLAIN di masing-masing kueri (yang GABUNG, lalu yang Subqueried), dan poskan hasilnya di sini.
Saya pikir melihat perbedaan dalam interpretasi MySQL dari pertanyaan-pertanyaan itu akan menjadi pengalaman belajar bagi semua orang.
sumber
Subquery mana harus menjalankan 1 kueri untuk setiap baris yang dikembalikan. Bergabung dalam hanya harus menjalankan 1 permintaan.
sumber
Subquery mungkin menjalankan "pemindaian tabel penuh". Dengan kata lain, tidak menggunakan indeks dan mengembalikan terlalu banyak baris yang harus disaring dari mana dari kueri utama.
Dugaan saja tanpa perincian tentu saja tapi itulah situasi umum.
sumber
Dengan subquery, Anda harus menjalankan kembali SELECT kedua untuk setiap hasil, dan setiap eksekusi biasanya mengembalikan 1 baris.
Dengan bergabung, SELECT kedua mengembalikan lebih banyak baris, tetapi Anda hanya perlu menjalankannya sekali. Keuntungannya adalah bahwa sekarang Anda dapat bergabung pada hasilnya, dan bergabung dengan relasi adalah apa yang seharusnya dimiliki oleh suatu database. Misalnya, mungkin pengoptimal dapat menemukan cara untuk memanfaatkan indeks dengan lebih baik sekarang.
sumber
Ini bukan subquery seperti klausa IN, meskipun bergabung pada fondasi dari setidaknya mesin SQL Oracle dan berjalan sangat cepat.
sumber
Diambil dari Referensi Manual ( 14.2.10.11 Subqueries Menulis Ulang sebagai Bergabung ):
Jadi subqueries bisa lebih lambat dari LEFT [OUTER] BERGABUNG.
sumber