Nhìn vào EXPLAIN
của bạn đầu ra, tôi lo ngại rằng việc bạn sử dụng các truy vấn con đã dẫn đến việc sử dụng các chỉ mục dưới mức tối ưu. Tôi cảm thấy (mà không có bất kỳ sự biện minh nào - và về điều này, tôi rất có thể đã sai) viết lại bằng cách sử dụng JOIN
có thể dẫn đến một truy vấn được tối ưu hóa hơn.
Để làm được điều đó, chúng tôi cần hiểu truy vấn của bạn dự định làm gì. Sẽ rất hữu ích nếu câu hỏi của bạn đã trình bày rõ ràng nó, nhưng sau một hồi đắn đo, tôi quyết định rằng truy vấn của bạn đang cố gắng tìm nạp danh sách tất cả các từ khóa khác xuất hiện trong bất kỳ bài viết nào có chứa một số từ khóa nhất định, cùng với một số của tất cả các bài viết có các từ khóa đó xuất hiện .
Bây giờ, hãy xây dựng lại truy vấn theo các giai đoạn:
-
Tìm nạp " bất kỳ bài viết nào có chứa một số từ khóa nhất định "(không lo trùng lặp):
SELECT ca2.article_id FROM career_article_keyword AS ca2 WHERE ca2.keyword_id = 9;
-
Tìm nạp " tất cả các từ khóa khác xuất hiện trong [ở trên] "
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;
-
Tìm nạp " [phần trên], cùng với tổng số tất cả các bài viết có các từ khóa đó xuất hiện "
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;
-
Cuối cùng, chúng tôi muốn thêm vào đầu ra chính từ khóa phù hợp từ
career_keyword
bảng: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;
Một điều rõ ràng ngay lập tức là truy vấn ban đầu của bạn đã tham chiếu đến career_keywords
hai lần, trong khi truy vấn được viết lại này chỉ tham chiếu đến bảng đó một lần; điều này chỉ có thể giải thích sự khác biệt về hiệu suất - hãy thử xóa tham chiếu thứ hai đến nó (tức là nơi nó xuất hiện trong truy vấn con đầu tiên của bạn), vì nó hoàn toàn dư thừa ở đó.
Nhìn lại truy vấn này, chúng ta có thể thấy rằng các phép nối đang được thực hiện trên các cột sau:
-
career_keywords.keyword_id
trongck JOIN ca0
Bảng này xác định
PRIMARY KEY (`keyword_id`)
, do đó, có một chỉ mục tốt có thể được sử dụng cho kết hợp này. -
career_article_keyword.article_id
trongca1 JOIN ca2
Bảng này xác định
UNIQUE KEY `article_id` (`article_id`,`keyword_id`)
và, kể từarticle_id
là cột ngoài cùng bên trái trong chỉ mục này, có một chỉ mục tốt có thể được sử dụng cho kết hợp này. -
career_article_keyword.keyword_id
trongck JOIN ca0
vàca0 JOIN ca1
Không có chỉ mục nào có thể được sử dụng cho kết hợp này:chỉ mục duy nhất được xác định trong bảng này có một cột khác,
article_id
ở bên trái củakeyword_id
- vì vậy MySQL không thể tìm thấykeyword_id
các mục trong chỉ mục mà không biếtarticle_id
trước . Tôi khuyên bạn nên tạo một chỉ mục mới cókeyword_id
là cột ngoài cùng bên trái của nó.(Nhu cầu về chỉ mục này có thể đã được xác định một cách bình đẳng trực tiếp từ việc xem xét truy vấn ban đầu của bạn, nơi hai truy vấn ngoài cùng của bạn thực hiện các phép nối trên cột đó.)