自上个月以来获取大多数评论的SQL查询

时间:2015-10-04 23:49:34

标签: sql postgresql

我有两个表,一个包含帖子,另一个包含评论,有数百万个帖子和100个百万条评论,评论表还包含帖子的ID。评论在一段时间后停用,我想知道哪些帖子在被停用之前的30天内评论最多。

我要做的是从评论表中找到每个帖子的最大值(comment_date),并从每个帖子的那个日期起1个月后计算所有评论。

基本上我想按post_id进行分组,找到max(comment_date)并计算每个帖子max(comment_date) - 1 month的所有评论。我正在努力创建查询以获取此数据?

数据库是postgres 9.4.1。

2 个答案:

答案 0 :(得分: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;

答案 1 :(得分:0)

我会尝试在这里使用LATERAL加入。如果您在comments上的(post_id, comment_date DESC)表上创建索引,则可能比Gordon Linoff建议的变体更有效。这实际上取决于您的数据分布。可能没有必要在索引中指定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天间隔内计算行数)。