我会尝试使用LATERAL
这里加入。如果您在(post_id, comment_date DESC)
上comments
表创建一个索引,它可能会比由戈登·利诺夫建议变种更有效。这真的取决于你的数据分布。它可能没有必要在索引中指定DESC
,优化器可能聪明地使用它,如果它是(post_id, comment_date ASC)
。但是,列的顺序很重要。
这里是SQL Fiddle。
查询字面上遵循问题中概述的步骤。
我们扫描posts
表一次。对于每篇文章,我们都会找到最新的comment_date
的评论,并从中减去30天。这应该通过寻求索引来完成。然后,我们会在找到日期减去30天后计算此帖子的所有评论。这应该通过范围索引扫描完成。
SELECT
posts.id
,c_count.post_count
FROM
posts
INNER JOIN LATERAL
(
SELECT comments.comment_date - interval '30 days' AS max_date
FROM comments
WHERE comments.post_id = posts.id
ORDER BY comments.comment_date DESC
LIMIT 1
) AS c_max_date ON true
INNER JOIN LATERAL
(
SELECT COUNT(*) AS post_count
FROM comments
WHERE
comments.post_id = posts.id
AND comments.comment_date >= c_max_date.max_date
) AS c_count ON true
;
它可能会利用窗口函数做两步一气呵成(发现最大日期,然后在30天的间隔内计算行)。
我不明白这个窗口函数的需要,不会选择c.post_id,max(comment_date)作为注释中的maxcd; group by post_id;'在子查询中工作相同? – rajat
@rajat。 。 。你将不得不将它加入到“评论”表中以获得你真正想要的数量。使用窗口函数应该有更好的性能。 –
@GordonLinoff,我将不胜感激,如果你可以看看我的回答这个问题。你怎么看 - 是否可以一起做两个步骤?是否有可能避免显式索引寻找“最大日期”,然后是“最大日期 - 30天”?我有一种感觉,像FIRST_VALUE这样的窗口函数可以做到这一点。 –