Betrachten Sie Ihr EXPLAIN
Ausgabe hatte ich Bedenken, dass Ihre Verwendung von Unterabfragen zu einer suboptimalen Verwendung von Indizes geführt hatte. Ich fühlte (ohne Begründung - und da kann ich mich sehr gut irren) dieses Umschreiben mit JOIN
kann zu einer optimierteren Abfrage führen.
Dazu müssen wir verstehen, was Ihre Anfrage bezwecken soll. Es hätte geholfen, wenn Ihre Frage es artikuliert hätte, aber nach ein wenig Kopfkratzen entschied ich, dass Ihre Abfrage versuchte, eine Liste aller anderen Schlüsselwörter abzurufen, die in jedem Artikel erscheinen, der ein bestimmtes Schlüsselwort enthält, zusammen mit einer Anzahl aller Artikel, in denen diese Schlüsselwörter vorkommen .
Lassen Sie uns nun die Abfrage schrittweise neu erstellen:
-
Rufen Sie "jeden Artikel ab, der ein bestimmtes Schlüsselwort enthält " (keine Sorge um Duplikate):
SELECT ca2.article_id FROM career_article_keyword AS ca2 WHERE ca2.keyword_id = 9;
-
Rufen Sie "alle anderen Schlüsselwörter ab, die in [oben] vorkommen "
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;
-
Rufen Sie "[das Obige] zusammen mit einer Anzahl aller Artikel ab, in denen diese Schlüsselwörter vorkommen "
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;
-
Schließlich wollen wir der Ausgabe das passende Schlüsselwort selbst aus dem
career_keyword
hinzufügen Tabelle: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;
Eine Sache, die sofort klar ist, ist, dass Ihre ursprüngliche Anfrage auf career_keywords
verwiesen hat zweimal, während diese umgeschriebene Abfrage diese Tabelle nur einmal referenziert; Dies allein könnte den Leistungsunterschied erklären - versuchen Sie, den zweiten Verweis darauf zu entfernen (d. h. dort, wo er in Ihrer ersten Unterabfrage erscheint), da er dort völlig überflüssig ist.
Wenn wir auf diese Abfrage zurückblicken, können wir sehen, dass Joins für die folgenden Spalten durchgeführt werden:
-
career_keywords.keyword_id
inck JOIN ca0
Diese Tabelle definiert
PRIMARY KEY (`keyword_id`)
, also gibt es einen guten Index, der für diesen Join verwendet werden kann. -
career_article_keyword.article_id
inca1 JOIN ca2
Diese Tabelle definiert
UNIQUE KEY `article_id` (`article_id`,`keyword_id`)
und seitarticle_id
die Spalte ganz links in diesem Index ist, gibt es einen guten Index, der für diesen Join verwendet werden kann. -
career_article_keyword.keyword_id
inck JOIN ca0
undca0 JOIN ca1
Es gibt keinen Index, der für diesen Join verwendet werden kann:Der einzige in dieser Tabelle definierte Index hat eine weitere Spalte,
article_id
links vonkeyword_id
- MySQL kann alsokeyword_id
nicht finden Einträge im Index, ohne vorher diearticle_id
zu kennen . Ich schlage vor, Sie erstellen einen neuen Index mitkeyword_id
als Spalte ganz links.(Die Notwendigkeit dieses Indexes hätte auch direkt durch Betrachten Ihrer ursprünglichen Abfrage festgestellt werden können, wo Ihre beiden äußersten Abfragen Joins für diese Spalte durchführen.)