Но почему? Вот запрос, получающий эту информацию:
SELECT MIN(p.name) name, count(*) cnt, p.idДля таблицы props (в дальнейшем p) есть индекс по полям up_id и tp, для таблицы article_props (в дальнейшем ap) — индекс по полю prop_id, ну а у таблицы articles (a) — первичный ключ по id. Но запрос сначала шел по таблице a (по индексу по полю is_can_show), затем по ap и по p. В таблице ap записей примерно в 5 раз меньше, чем в p, может быть по-этому анализатор выбирал сначала эту таблицу.
FROM props p
,article_props ap
,articles a
WHERE p.up_id = 171
AND p.tp = 'P'
AND p.id = ap.prop_id
AND ap.art_id = a.id
AND a.is_can_show = 'Y'
GROUP BY p.id
Знаток MySQL рекомендовал мне:
- переписываем с оракловского синтаксиса на общечеловеческий, расставляя таблицы в желаемом порядке
SELECT MIN(p.name) name, count(*) cnt, p.id
FROM props p
INNER JOIN article_props ap ON p.id = ap.prop_id
INNER JOIN articles a ON (ap.art_id = a.id AND a.is_can_show = 'Y')
WHERE p.up_id = 171
AND p.tp = 'P'
GROUP BY p.id - Применить хинт
SELECT /*+ORDERED*/ ...
- А лучше переделать все на LEFT JOIN
SELECT /*+ORDERED*/
MIN(p.name) name, count(*) cnt, p.id
FROM props p
LEFT JOIN article_props ap ON p.id = ap.prop_id
LEFT JOIN articles a ON (ap.art_id = a.id AND a.is_can_show = 'Y')
WHERE p.up_id = 171
AND p.tp = 'P'
AND a.id IS NOT NULL
GROUP BY p.id
Потому что LEFT JOIN как раз диктует порядок построения запроса и не даёт оптимизатору умничать. ВСЕГДА ставьте LEFT JOIN. Почувствуйте себя хозяином положения».
И действительно, после этих манипуляций запрос «пошёл» по нужным индексам, и стал отрабатывать за 0.6 секунды, вместо 9.6.
Я создал все страницы, на что ушло около 15 минут, начал проверять что получилось, и заметил, что запрос-то ошибочный. При его выполнении выдаются все записи из таблицы p, даже те, для которых нет ссылок в ap. При замене первого LEFT JOIN article_props ap ON p.id = ap.prop_id на INNER JOIN и эта проблема была решена. Но все же, использование LEFT JOIN меня сильно коробило. Не красиво это.
И элегантное решение было найдено. Оказывается, в MySQL есть возможность указания индексов в хинтах. В результате запрос стал
SELECT MIN(p.name) name, count(*) cnt, p.id24 отзыва вместе с индексными файлами созданы менее чем за 12 секунд (сравните со 120 секундами до оптимизации).
FROM props p,
article_props ap,
articles a IGNORE INDEX(art_is_can_show_i)
WHERE p.up_id = 171
AND p.tp = 'P'
AND p.id = ap.prop_id
AND ap.art_id = a.id
AND a.is_can_show = 'Y'
GROUP BY p.id
Полезно, спасибо.
ОтветитьУдалить