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_keyword
tafel: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_id
inck JOIN ca0
Deze tabel definieert
PRIMARY KEY (`keyword_id`)
, dus er is een goede index die voor deze join kan worden gebruikt. -
career_article_keyword.article_id
inca1 JOIN ca2
Deze tabel definieert
UNIQUE KEY `article_id` (`article_id`,`keyword_id`)
en, sindsarticle_id
is de meest linkse kolom in deze index, er is een goede index die voor deze join kan worden gebruikt. -
career_article_keyword.keyword_id
inck JOIN ca0
enca0 JOIN ca1
Er is geen index die voor deze join kan worden gebruikt:de enige index die in deze tabel is gedefinieerd, heeft een andere kolom,
article_id
links vankeyword_id
- dus MySQL kankeyword_id
niet vinden vermeldingen in de index zonder eerst dearticle_id
. te kennen . Ik raad u aan een nieuwe index te maken metkeyword_id
als 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.)