У меня есть несколько таблиц php-доски.
Мне нужен эффективный запрос, чтобы выбрать все категории, все темы, последнее сообщение из тем, с опубликованным пользователем. По моему запросу на его выполнение уходит 5-8 секунд.
Я выполнил оптимизацию с помощью поля last_post_id в таблице тем, но мне нужно лучшее решение для него.
Состав
forum_categories ~ 15 lines
id|name|...
forum_topics ~ 150 lines
id|name|category_id|...
forum_posts ~ 1.000.000 lines
id|body|topic_id|user_id|...
users ~ 30.000 lines
id|username|...category 1
- topic 1
- last post1 | user1
- topic 2
- last post2 | user2
...
category 2
- topic 3
- last post3 | user3
...
...
Последний запрос (Это была помощь моего друга. Но это также было так медленно.)
SELECT c.NAME AS category,
t.NAME AS topic,
p.body AS post,
p.username AS username
FROM forum_categories AS c
JOIN forum_topics AS t
ON t.category_id = c.id
JOIN (SELECT *
FROM (SELECT p.body,
p.topic_id,
u.username
FROM forum_posts AS p
JOIN users AS u
ON u.id = p.user_id
ORDER BY p.id DESC) AS t
GROUP BY topic_id) AS p
ON t.id = p.topic_id
Объясните запрос
Статистика запроса
Заголовки: сортировка, статус, время | статус, все время, pct. время, звонки, время
Я думаю «последний пост из тем» является ключевой точкой вашего запроса. Вот почему вы использовали ORDER BY
на большинстве внутренних запросов, но это делает два подзапроса.
CREATE TEMPORARY TABLE last_post_per_topic_t ENGINE = MEMORY
SELECT topic_id, MAX(id) AS id -----+
FROM forum_posts --> find last post id per topic
GROUP BY topic_id; -----------------+
ALTER TABLE last_post_per_topic_t ADD INDEX (id, topic_id);
SELECT *
FROM forum_categories AS c INNER JOIN forum_topics t ON c.id = t.category_id
INNER JOIN forum_posts p ON p.topic_id = t.id
INNER JOIN last_post_per_topic_t ON last_post_per_topic_t.topic_id = t.id
AND last_post_per_topic_t.id = p.id;
INNER JOIN users u ON p.user_id = u.id;
SELECT *
FROM forum_categories AS c INNER JOIN forum_topics t ON c.id = t.category_id
INNER JOIN forum_posts p ON p.topic_id = t.id
INNER JOIN (
SELECT topic_id, MAX(id) AS id -----+
FROM forum_posts --- find last post_id per topic
GROUP BY topic_id ---------------+
) last_post_per_topic_t ON last_post_per_topic_t.topic_id = t.id
AND last_post_per_topic_t.id = p.id;
Других решений пока нет …