2015-10-04 53 views
1

我有两个表,其中一个包含帖子和其他包含评论,有数百万的帖子和数百万的评论,评论表还包含帖子的ID。评论在一段时间后停用,我想知道哪些帖子在被停用之前最近30天内的评论最多。SQL查询以获得自上个月以来最多的评论

我需要做的是从评论表中找到每篇文章的max(comment_date),并计算每篇文章从该日期起1个月后的所有评论。

所以基本上我通过post_id想组,找到max(comment_date)max(comment_date) - 1 month获得的所有评论计数每一个职位。我正在努力创建查询来获取这些数据?

数据库是postgres 9.4.1。

回答

2

在数据的量,查询需要一定的时间。一种方法是使用窗口功能:

select post_id, count(*) 
from (select c.*, max(comment_date) over (partition by post_id) as maxcd 
     from comments c 
    ) c 
where comment_date >= maxcd - interval '1 month' 
group by post_id; 
+0

我不明白这个窗口函数的需要,不会选择c.post_id,max(comment_date)作为注释中的maxcd; group by post_id;'在子查询中工作相同? – rajat

+0

@rajat。 。 。你将不得不将它加入到“评论”表中以获得你真正想要的数量。使用窗口函数应该有更好的性能。 –

+0

@GordonLinoff,我将不胜感激,如果你可以看看我的回答这个问题。你怎么看 - 是否可以一起做两个步骤?是否有可能避免显式索引寻找“最大日期”,然后是“最大日期 - 30天”?我有一种感觉,像FIRST_VALUE这样的窗口函数可以做到这一点。 –

0

我会尝试使用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天的间隔内计算行)。

相关问题