Melihat EXPLAIN
output, saya khawatir bahwa penggunaan subquery Anda telah mengakibatkan penggunaan indeks yang tidak optimal. Saya merasa (tanpa pembenaran apa pun - dan dalam hal ini saya mungkin salah) yang menulis ulang menggunakan JOIN
mungkin mengarah ke kueri yang lebih optimal.
Untuk melakukan itu, kami perlu memahami apa yang dimaksudkan untuk dilakukan oleh kueri Anda. Akan membantu jika pertanyaan Anda telah mengartikulasikannya, tetapi setelah sedikit menggaruk-garuk kepala, saya memutuskan bahwa kueri Anda mencoba mengambil daftar semua kata kunci lain yang muncul di artikel mana pun yang berisi beberapa kata kunci tertentu, bersama dengan hitungan dari semua artikel di mana kata kunci tersebut muncul .
Sekarang mari kita buat ulang kueri secara bertahap:
-
Ambil "artikel apa pun yang berisi beberapa kata kunci tertentu " (tidak khawatir tentang duplikat):
SELECT ca2.article_id FROM career_article_keyword AS ca2 WHERE ca2.keyword_id = 9;
-
Ambil "semua kata kunci lain yang muncul di [di atas] "
SELECT ca1.keyword_id FROM career_article_keyword AS ca1 JOIN career_article_keyword AS ca2 ON (ca2.article_id = ca1.article_id) WHERE ca1.keyword_id <> 9 AND ca2.keyword_id = 9 GROUP BY ca1.keyword_id;
-
Ambil "[yang di atas], bersama dengan jumlah semua artikel di mana kata kunci tersebut muncul "
SELECT ca1.keyword_id, COUNT(DISTINCT ca0.article_id) AS cnt FROM career_article_keyword AS ca0 JOIN career_article_keyword AS ca1 USING (keyword_id) JOIN career_article_keyword AS ca2 ON (ca2.article_id = ca1.article_id) WHERE ca1.keyword_id <> 9 AND ca2.keyword_id = 9 GROUP BY ca1.keyword_id ORDER BY cnt DESC;
-
Terakhir, kami ingin menambahkan ke output kata kunci yang cocok itu sendiri dari
career_keyword
tabel:SELECT ck.keyword_id, ck.keyword, COUNT(DISTINCT ca0.article_id) AS cnt FROM career_keywords AS ck JOIN career_article_keyword AS ca0 USING (keyword_id) JOIN career_article_keyword AS ca1 USING (keyword_id) JOIN career_article_keyword AS ca2 ON (ca2.article_id = ca1.article_id) WHERE ca1.keyword_id <> 9 AND ca2.keyword_id = 9 GROUP BY ck.keyword_id -- equal to ca1.keyword_id due to join conditions ORDER BY cnt DESC;
Satu hal yang segera jelas adalah bahwa kueri asli Anda mereferensikan career_keywords
dua kali, sedangkan kueri yang ditulis ulang ini merujuk tabel itu hanya sekali; ini saja mungkin menjelaskan perbedaan kinerja - coba hapus referensi kedua untuk itu (yaitu di mana ia muncul di subkueri pertama Anda), karena sepenuhnya berlebihan di sana.
Melihat kembali kueri ini, kita dapat melihat bahwa penggabungan sedang dilakukan pada kolom berikut:
-
career_keywords.keyword_id
dick JOIN ca0
Tabel ini mendefinisikan
PRIMARY KEY (`keyword_id`)
, jadi ada indeks bagus yang bisa digunakan untuk bergabung ini. -
career_article_keyword.article_id
dica1 JOIN ca2
Tabel ini mendefinisikan
UNIQUE KEY `article_id` (`article_id`,`keyword_id`)
dan, karenaarticle_id
adalah kolom paling kiri dalam indeks ini, ada indeks bagus yang dapat digunakan untuk bergabung ini. -
career_article_keyword.keyword_id
dick JOIN ca0
danca0 JOIN ca1
Tidak ada indeks yang dapat digunakan untuk penggabungan ini:satu-satunya indeks yang ditentukan dalam tabel ini memiliki kolom lain,
article_id
di sebelah kirikeyword_id
- jadi MySQL tidak dapat menemukankeyword_id
entri dalam indeks tanpa terlebih dahulu mengetahuiarticle_id
. Saya sarankan Anda membuat indeks baru yang memilikikeyword_id
sebagai kolom paling kiri.(Kebutuhan indeks ini sama-sama dapat dipastikan langsung dari melihat kueri asli Anda, di mana dua kueri terluar Anda melakukan penggabungan pada kolom itu.)