Podívejte se na svůj EXPLAIN
výstup, měl jsem obavy, že vaše použití poddotazů vedlo k neoptimálnímu použití indexů. cítil jsem (bez jakéhokoli odůvodnění - a v tomto se mohu velmi dobře mýlit), že přepisování pomocí JOIN
může vést k optimalizaci dotazu.
Abychom to mohli udělat, musíme pochopit, k čemu je váš dotaz určen. Pomohlo by, kdyby to vaše otázka formulovala, ale po malém přemýšlení jsem usoudil, že se váš dotaz pokouší načíst seznam všech ostatních klíčových slov, která se vyskytují v jakémkoli článku, který obsahuje nějaké dané klíčové slovo, spolu s počtem všech článků, ve kterých se tato klíčová slova vyskytují .
Nyní znovu sestavíme dotaz ve fázích:
-
Načtěte „jakýkoli článek, který obsahuje určité klíčové slovo " (nestarejte se o duplikáty):
SELECT ca2.article_id FROM career_article_keyword AS ca2 WHERE ca2.keyword_id = 9;
-
Načtěte „všechna ostatní klíčová slova, která se vyskytují v [výše] "
."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;
-
Načíst [výše uvedené] spolu s počtem všech článků, ve kterých se tato klíčová slova vyskytují "
."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;
-
Nakonec chceme do výstupu přidat samotné odpovídající klíčové slovo z
career_keyword
tabulka: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;
Jedna věc, která je hned jasná, je, že váš původní dotaz odkazoval na career_keywords
dvakrát, zatímco tento přepsaný dotaz odkazuje na tuto tabulku pouze jednou; to samo o sobě může vysvětlit rozdíl ve výkonu – zkuste odstranit druhý odkaz na něj (tj. tam, kde se vyskytuje ve vašem prvním dílčím dotazu), protože je tam zcela nadbytečný.
Při pohledu zpět na tento dotaz můžeme vidět, že spojení se provádějí v následujících sloupcích:
-
career_keywords.keyword_id
vck JOIN ca0
Tato tabulka definuje
PRIMARY KEY (`keyword_id`)
, takže existuje dobrý index, který lze pro toto spojení použít. -
career_article_keyword.article_id
vca1 JOIN ca2
Tato tabulka definuje
UNIQUE KEY `article_id` (`article_id`,`keyword_id`)
a odarticle_id
je sloupec zcela vlevo v tomto indexu, existuje dobrý index, který lze pro toto spojení použít. -
career_article_keyword.keyword_id
vck JOIN ca0
aca0 JOIN ca1
Neexistuje žádný index, který lze pro toto spojení použít:jediný index definovaný v této tabulce má další sloupec,
article_id
nalevo odkeyword_id
- takže MySQL nemůže najítkeyword_id
položky v indexu, aniž byste nejprve znaliarticle_id
. Navrhuji, abyste vytvořili nový index, který mákeyword_id
jako jeho sloupec zcela vlevo.(Potřeba tohoto indexu mohla být rovněž zjištěna přímo z vašeho původního dotazu, kde vaše dva nejvzdálenější dotazy provádějí spojení v tomto sloupci.)