EXPLAIN
を見てください 出力では、サブクエリを使用すると、インデックスの使用が最適ではなくなるのではないかと心配していました。 感じた (正当な理由なしに-そしてこれについては私は非常に間違っているかもしれません)JOIN
を使用して書き直す より最適化されたクエリにつながる可能性があります。
そのためには、クエリの目的を理解する必要があります。あなたの質問がそれを明確に表現していれば助けになったでしょうが、少し頭を悩ませた後、あなたのクエリは、特定のキーワードを含む記事に表示される他のすべてのキーワードのリストを、カウントとともにフェッチしようとしていると判断しましたそれらのキーワードが表示されるすべての記事の 。
それでは、クエリを段階的に再構築しましょう:
-
「特定のキーワードを含む記事」を取得します "(重複について心配する必要はありません):
SELECT ca2.article_id FROM career_article_keyword AS ca2 WHERE ca2.keyword_id = 9;
-
"[上記]に表示される他のすべてのキーワードを取得します "
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;
-
「[上記]と、それらのキーワードが表示されているすべての記事の数を取得 "
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;
-
最後に、
career_keyword
からの一致するキーワード自体を出力に追加します。 テーブル: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;
すぐにわかることの1つは、元のクエリがcareer_keywords
を参照していることです。 2回ですが、この書き直されたクエリはそのテーブルを1回だけ参照します。これだけでパフォーマンスの違いを説明できるかもしれません-完全に冗長であるため、それへの2番目の参照(つまり、最初のサブクエリで表示される場所)を削除してみてください。
このクエリを振り返ると、次の列で結合が実行されていることがわかります。
-
career_keywords.keyword_id
ck JOIN ca0
でこのテーブルは、
PRIMARY KEY (`keyword_id`)
を定義します 、したがって、この結合に使用できる優れたインデックスがあります。 -
career_article_keyword.article_id
ca1 JOIN ca2
でこのテーブルは、
UNIQUE KEY `article_id` (`article_id`,`keyword_id`)
を定義します。 そして、article_id
以降 はこのインデックスの左端の列であり、この結合に使用できる適切なインデックスがあります。 -
career_article_keyword.keyword_id
ck JOIN ca0
で およびca0 JOIN ca1
この結合に使用できるインデックスはありません。このテーブルで定義されている唯一のインデックスには、別の列
article_id
があります。keyword_id
の左側 --MySQLはkeyword_id
を見つけることができませんarticle_id
を最初に知らなくてもインデックスのエントリ 。keyword_id
を持つ新しいインデックスを作成することをお勧めします 左端の列として。(このインデックスの必要性は、2つの最も外側のクエリがその列で結合を実行する元のクエリを調べることからも同様に直接確認できます。)