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_keyword
tabel: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_id
ick JOIN ca0
Denne tabel definerer
PRIMARY KEY (`keyword_id`)
, så der er et godt indeks, som kan bruges til denne join. -
career_article_keyword.article_id
ica1 JOIN ca2
Denne tabel definerer
UNIQUE KEY `article_id` (`article_id`,`keyword_id`)
og sidenarticle_id
er kolonnen længst til venstre i dette indeks, er der et godt indeks, som kan bruges til denne join. -
career_article_keyword.keyword_id
ick JOIN ca0
ogca0 JOIN ca1
Der er intet indeks, der kan bruges til denne joinforbindelse:det eneste indeks, der er defineret i denne tabel, har en anden kolonne,
article_id
til venstre forkeyword_id
- så MySQL kan ikke findekeyword_id
poster i indekset uden først at kendearticle_id
. Jeg foreslår, at du opretter et nyt indeks, som harkeyword_id
som 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.)