Tittar på din EXPLAIN
output, var jag orolig för att din användning av underfrågor hade resulterat i en suboptimal användning av index. Jag kände (utan någon motivering - och om detta kan jag mycket väl ha fel) denna omskrivning med JOIN
kan leda till en mer optimerad fråga.
För att göra det måste vi förstå vad det är din fråga är avsedd att göra. Det skulle ha hjälpt om din fråga hade formulerat det, men efter lite huvudskrapa bestämde jag mig för att din fråga försökte hämta en lista över alla andra sökord som förekommer i en artikel som innehåller ett givet nyckelord, tillsammans med en räkning av alla artiklar där dessa sökord förekommer .
Låt oss nu bygga om frågan i etapper:
-
Hämta "alla artiklar som innehåller ett visst sökord " (inte oroa dig för dubbletter):
SELECT ca2.article_id FROM career_article_keyword AS ca2 WHERE ca2.keyword_id = 9;
-
Hämta "alla andra sökord som visas i [ovan] "
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;
-
Hämta "[ovanstående], tillsammans med en räkning av alla artiklar där dessa sökord förekommer "
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;
-
Slutligen vill vi lägga till själva det matchande sökordet från
career_keyword
till utdata tabell: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 sak som är omedelbart tydlig är att din ursprungliga fråga refererade till career_keywords
två gånger, medan denna omskrivna fråga endast refererar till den tabellen en gång; Bara detta kan förklara prestandaskillnaden – försök att ta bort den andra referensen till den (dvs. där den visas i din första underfråga), eftersom den är helt överflödig där.
När vi ser tillbaka på den här frågan kan vi se att kopplingar utförs i följande kolumner:
-
career_keywords.keyword_id
ick JOIN ca0
Den här tabellen definierar
PRIMARY KEY (`keyword_id`)
, så det finns ett bra index som kan användas för denna join. -
career_article_keyword.article_id
ica1 JOIN ca2
Den här tabellen definierar
UNIQUE KEY `article_id` (`article_id`,`keyword_id`)
och eftersomarticle_id
är kolumnen längst till vänster i detta index, det finns ett bra index som kan användas för denna koppling. -
career_article_keyword.keyword_id
ick JOIN ca0
ochca0 JOIN ca1
Det finns inget index som kan användas för denna koppling:det enda indexet som definieras i den här tabellen har en annan kolumn,
article_id
till vänster omkeyword_id
- så MySQL kan inte hittakeyword_id
poster i indexet utan att först känna tillarticle_id
. Jag föreslår att du skapar ett nytt index som harkeyword_id
som kolumn längst till vänster.(Behovet av detta index kunde likaså ha fastställts direkt genom att titta på din ursprungliga fråga, där dina två yttersta frågor utför kopplingar på den kolumnen.)