Kijken naar je EXPLAIN output, was ik bang dat uw gebruik van subquery's had geresulteerd in een suboptimaal gebruik van indexen. Ik voelde (zonder enige rechtvaardiging - en hierin kan ik me vergissen) dat herschrijven met JOIN kan leiden tot een meer geoptimaliseerde zoekopdracht.
Om dat te doen, moeten we begrijpen waarvoor uw zoekopdracht is bedoeld. Het zou hebben geholpen als je vraag het had verwoord, maar na een beetje hoofdbrekens besloot ik dat je zoekopdracht probeerde om een lijst op te halen van alle andere trefwoorden die voorkomen in een artikel dat een bepaald trefwoord bevat, samen met een telling van alle artikelen waarin die zoekwoorden voorkomen .
Laten we de query nu in fasen opnieuw opbouwen:
-
Haal "elk artikel op dat een bepaald zoekwoord bevat " (geen zorgen over duplicaten):
SELECT ca2.article_id FROM career_article_keyword AS ca2 WHERE ca2.keyword_id = 9; -
Haal "alle andere zoekwoorden op die in [het bovenstaande] voorkomen "
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; -
Haal "[het bovenstaande] op, samen met een telling van alle artikelen waarin die zoekwoorden voorkomen "
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; -
Ten slotte willen we aan de uitvoer het overeenkomende trefwoord zelf toevoegen uit het
career_keywordtafel: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;
Een ding dat meteen duidelijk is, is dat uw oorspronkelijke zoekopdracht verwijst naar career_keywords twee keer, terwijl deze herschreven query slechts één keer naar die tabel verwijst; dit alleen al zou het prestatieverschil kunnen verklaren - probeer de tweede verwijzing ernaar te verwijderen (d.w.z. waar het voorkomt in uw eerste subquery), aangezien het daar volledig overbodig is.
Als we terugkijken op deze zoekopdracht, kunnen we zien dat er samenvoegingen worden uitgevoerd op de volgende kolommen:
-
career_keywords.keyword_idinck JOIN ca0Deze tabel definieert
PRIMARY KEY (`keyword_id`), dus er is een goede index die voor deze join kan worden gebruikt. -
career_article_keyword.article_idinca1 JOIN ca2Deze tabel definieert
UNIQUE KEY `article_id` (`article_id`,`keyword_id`)en, sindsarticle_idis de meest linkse kolom in deze index, er is een goede index die voor deze join kan worden gebruikt. -
career_article_keyword.keyword_idinck JOIN ca0enca0 JOIN ca1Er is geen index die voor deze join kan worden gebruikt:de enige index die in deze tabel is gedefinieerd, heeft een andere kolom,
article_idlinks vankeyword_id- dus MySQL kankeyword_idniet vinden vermeldingen in de index zonder eerst dearticle_id. te kennen . Ik raad u aan een nieuwe index te maken metkeyword_idals de meest linkse kolom.(De behoefte aan deze index kan ook direct worden vastgesteld door naar uw oorspronkelijke zoekopdracht te kijken, waar uw twee buitenste zoekopdrachten samenvoegingen uitvoeren op die kolom.)