I have MySQL database and 5 tables called tribes(groups)
, posts
, posts_to_groups
, post_comments
and posts_votes
.
Relationship between groups and posts is MANY_2_MANY so each post can belong to many groups and each group can contain 0-* posts. This is what table posts_to_groups does.
I'm searching for the 3 most popular posts that were posted into the groups that this user follows(associated via posts_to_tribes - table for MANY_2_MANY relationship) for the last 24 hours from this moment and ordered by sum of (comments_count + votes_count) DESC
This is my current query:
SELECT DISTINCT
p.post_id,
p.description,
p.link,
p.user_id,
p.total_comments,
p.total_votes,
(SELECT
COUNT(*)
FROM
comments
WHERE
last_edited > DATE_SUB(NOW(), INTERVAL 24 HOUR)
AND post_id = p.post_id) AS comments_count,
(SELECT
COUNT(*)
FROM
posts_votes
WHERE
date_voted > DATE_SUB(NOW(), INTERVAL 24 HOUR)
AND post_id = p.post_id) AS votes_count
FROM
posts p
JOIN
posts_to_tribes pt ON pt.post_id = p.post_id
WHERE
pt.tribe_id IN (3 , 38, 107)
ORDER BY (comments_count + votes_count) DESC , p.last_edited DESC
LIMIT 3;
This query is extremely slow and took right now ~500ms.
Is any way to rewrite this query in order to improve performance ?
UPDATED:
EXPLAIN output:
Query suggested by Tim3880:
SELECT
p.post_id,
p.description,
p.link,
p.user_id,
p.total_comments,
p.total_votes,
t.comments_count,
t.votes_count
FROM posts p
JOIN (
SELECT
p.post_id,
(SELECT
COUNT(*)
FROM
comments
WHERE
last_edited > DATE_SUB(NOW(), INTERVAL 24 HOUR)
AND post_id = p.post_id) AS comments_count,
(SELECT
COUNT(*)
FROM
posts_votes
WHERE
date_voted > DATE_SUB(NOW(), INTERVAL 24 HOUR)
AND post_id = p.post_id) AS votes_count
FROM
posts p
JOIN
posts_to_tribes pt ON pt.post_id = p.post_id
WHERE
pt.tribe_id IN (3 , 38, 107)
ORDER BY (comments_count + votes_count) DESC , p.last_edited DESC
LIMIT 3
) t
ON p.post_id = t.post_id
ORDER BY (t.comments_count + t.votes_count) DESC , p.last_edited DESC
It took now ~280ms.
EXPLAIN output: