2015-06-16 3 views
0

У меня есть следующий запрос: MySQLMySQL JOIN/IN оптимизации производительности

SELECT 
    p.post_id, 
    p.date_created, 
    p.description, 
    p.last_edited, 
    p.link, 
    p.link_description, 
    p.link_image_url, 
    p.link_title, 
    p.total_comments, 
    p.total_votes, 
    p.type_id, 
    p.user_id 
FROM posts p JOIN posts_to_tribes ptt ON p.post_id=ptt.post_id 
WHERE ptt.tribe_id IN (1, 2, 3, 4, 5) 
GROUP BY p.post_id 
ORDER BY p.last_edited DESC, p.total_votes DESC LIMIT 25 

В не-параллельной среде работает этот запрос ~ 172ms, но в параллельной среде работает 1-2 сек (во время тестирования производительности).

EXPLAIN выход:

enter image description here

Индексы на столе posts_to_tribes:

enter image description here

Есть ли способ для того, чтобы улучшить производительность здесь?

+0

там может быть индекс ptt.tribe_id –

+0

Основное правило: любое поле, используемое в контексте «решения» (присоединиться, где, упорядочить по) должны иметь индекс на нем. –

+0

Спасибо за ваши ответы, я добавил индекс на posts_to_tribes.tribe_id, но ничего не изменилось .. запрос работает ~ 188ms прямо сейчас .. может быть, я делаю что-то неправильно .. – alexanoid

ответ

1

Вам нужен композитный индекс для posts_to_tribes: INDEX(tribe_id, post_id).

GROUP BY должен был компенсировать JOIN, взорвав количество строк. Вот лучше обходной путь, чем IN (SELECT ...):

SELECT p.post_id, p.date_created, p.description, p.last_edited, 
     p.link, p.link_description, p.link_image_url, p.link_title, 
     p.total_comments, p.total_votes, p.type_id, p.user_id 
    FROM posts p 
    JOIN 
     (SELECT DISTINCT post_id 
      FROM posts_to_tribes 
      WHERE tribe_id IN (1, 2, 3, 4, 5) 
    ) AS ptt USING (post_id) 
    ORDER BY p.last_edited DESC, 
       p.total_votes DESC 
    LIMIT 25 
+0

Большое спасибо! Этот запрос работает ~ 140 мс – alexanoid

+0

Еще один вопрос: нужны ли нам индексы на p.last_edited и p.total_votes? – alexanoid

+0

Нет. Я не считаю, что 'INDEX (last_edited, total_votes)' (композитный, в указанном порядке) будет делать что угодно. (1) Он начнется с подзапроса, который не позволит ему перейти к этому индексу.(2) Звучат похожие столбцы, которые будут сильно изменены, поэтому накладные расходы в 'UPDATE'. Вы застряли с файловым контентом. –

1

Вы применили JOIN операцию, когда вы действительно хотите применить semi-join между вашими двумя таблицами (Полусоединением в SQL реализован с использованием IN или EXISTS предикатов).

Поскольку вы использовали неправильный тип JOIN, вы снова удалили дубликаты записей, используя GROUP BY. Там очень много запущенных циклов процессора.

Следующий запрос будет намного быстрее:

SELECT 
    p.post_id, 
    p.date_created, 
    p.description, 
    p.last_edited, 
    p.link, 
    p.link_description, 
    p.link_image_url, 
    p.link_title, 
    p.total_comments, 
    p.total_votes, 
    p.type_id, 
    p.user_id 
FROM posts p 
WHERE p.post_id IN (
    SELECT ptt.post_id 
    FROM posts_to_tribes ptt 
    WHERE ptt.tribe_id IN (1, 2, 3, 4, 5) 
) 
ORDER BY p.last_edited DESC, p.total_votes DESC LIMIT 25 

Вы все еще должны иметь индексы на (p.post_id) и (ptt.tribe_id, ptt.post_id)

+0

Спасибо, теперь этот запрос работает ~ 156 мс. Также я проверю его на своем тестирование производительности в параллельной среде – alexanoid

+0

Вы указали указатель на оба столбца 'ptt', как я указал? –

+0

В posts_to_tribes У меня есть PK на (tribe_id, post_id). Также в таблице сообщений post_id также является PK. Должен ли я добавить отдельный индекс в эти поля? – alexanoid

Смежные вопросы