Ser på din EXPLAIN output, var jeg bekymret for, at din brug af underforespørgsler havde resulteret i en suboptimal brug af indekser. Jeg følte (uden nogen begrundelse - og her kan jeg meget vel tage fejl) denne omskrivning ved hjælp af JOIN kan føre til en mere optimeret forespørgsel.
For at gøre det skal vi forstå, hvad det er, din forespørgsel er beregnet til. Det ville have hjulpet, hvis dit spørgsmål havde formuleret det, men efter lidt hovedskraber besluttede jeg, at din forespørgsel forsøgte at hente en liste over alle andre søgeord, der vises i en artikel, der indeholder et givet søgeord, sammen med et antal af alle artikler, hvor disse søgeord forekommer .
Lad os nu genopbygge forespørgslen i etaper:
-
Hent "enhver artikel, der indeholder et givet søgeord " (ikke bekymre dig om dubletter):
SELECT ca2.article_id FROM career_article_keyword AS ca2 WHERE ca2.keyword_id = 9; -
Hent "alle andre søgeord, der vises i [ovenstående] "
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; -
Hent "[ovenstående], sammen med en optælling af alle artikler, hvori disse søgeord forekommer "
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; -
Til sidst vil vi tilføje selve det matchende søgeord til outputtet fra
career_keywordtabel: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;
En ting, der umiddelbart står klart, er, at din oprindelige forespørgsel refererede til career_keywords to gange, hvorimod denne omskrevne forespørgsel kun refererer til denne tabel én gang; dette alene kan forklare ydeevneforskellen - prøv at fjerne den anden reference til den (dvs. hvor den vises i din første underforespørgsel), da den er helt overflødig der.
Når vi ser tilbage på denne forespørgsel, kan vi se, at joinforbindelser udføres i følgende kolonner:
-
career_keywords.keyword_idick JOIN ca0Denne tabel definerer
PRIMARY KEY (`keyword_id`), så der er et godt indeks, som kan bruges til denne join. -
career_article_keyword.article_idica1 JOIN ca2Denne tabel definerer
UNIQUE KEY `article_id` (`article_id`,`keyword_id`)og sidenarticle_ider kolonnen længst til venstre i dette indeks, er der et godt indeks, som kan bruges til denne join. -
career_article_keyword.keyword_idick JOIN ca0ogca0 JOIN ca1Der er intet indeks, der kan bruges til denne joinforbindelse:det eneste indeks, der er defineret i denne tabel, har en anden kolonne,
article_idtil venstre forkeyword_id- så MySQL kan ikke findekeyword_idposter i indekset uden først at kendearticle_id. Jeg foreslår, at du opretter et nyt indeks, som harkeyword_idsom kolonnen længst til venstre.(Behovet for dette indeks kunne ligeledes have været konstateret direkte ved at se på din oprindelige forespørgsel, hvor dine to yderste forespørgsler udfører joinforbindelser på den kolonne.)