2015-10-04 2 views
1

У меня есть две таблицы, одна из которых содержит сообщения и другие, содержащие комментарии. Есть миллионы сообщений и 100 миллионов комментариев, в таблице комментариев также содержатся идентификаторы сообщения. Комментарии деактивируются через некоторое время, я хочу знать, какие сообщения имели наибольшее количество комментариев за последние 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

Я не понимаю необходимость функции окна для этого, не будет 'select c.post_id, max (comment_date) как maxcd из комментариев; group by post_id; 'работать то же самое в подзапросе? – rajat

+0

@rajat. , , Вам нужно будет присоединиться к нему в таблице 'comments', чтобы получить счет, который вы действительно хотите. Использование оконных функций должно иметь лучшую производительность. –

+0

@GordonLinoff, я был бы признателен, если бы вы могли взглянуть на мой ответ на этот вопрос. Как вы думаете, можно ли сделать два шага вместе? Можно ли избежать явного поиска индекса для «максимальной даты», а затем для «максимальной даты - 30 дней»? У меня такое ощущение, что функция окна, такая как 'FIRST_VALUE', может сделать трюк. –

0

Я хотел бы попробовать использовать LATERAL присоединиться здесь. Если вы создадите индекс на таблице comments на (post_id, comment_date DESC), он может быть более эффективным, чем вариант, предложенный Гордоном Линоффом. Это зависит от вашего распределения данных. Возможно, нет необходимости указывать в индексе 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 дней интервала) с использованием оконных функций.

Смежные вопросы