Postgres - 从月末最后一天总结行的快速方法

时间:2016-11-09 18:37:07

标签: sql performance postgresql date

我想查询一个表,并为该月最后一天的所有行汇总一列。

让我们使用下表作为示例:

CREATE TABLE example(dt date, value int)

(真正的表有更多的列,并且相对较大,真正的查询更复杂)

我有以下查询:

SELECT dt, SUM(value)
FROM example
WHERE dt IN  (SELECT DISTINCT
     date_trunc('MONTH', generate_series('2012-01-01'::date,
                                         '2016-12-01'::date,
                                         interval '1 day') + INTERVAL '1 MONTH - 1 day')::date)
GROUP BY dt

它在我的真实桌子上运行约2秒钟。

但是,如果我在我的范围内生成月末日的完整列表,并像这样参数化查询:

SELECT dt, SUM(value)
FROM example
WHERE dt IN ('2012-01-31', ...)
GROUP BY dt

它快得多,约750毫秒。

我不想生成日期并将它们传递给查询,就像那样,有没有办法可以在SQL中完全执行此操作并使其与后一版本一样快?

2 个答案:

答案 0 :(得分:0)

子选择不必要地复杂化。它可以简化为:

SELECT dt, SUM(value)
FROM example
WHERE dt IN (SELECT d::date
             from generate_series('2012-01-01'::date, '2016-12-01'::date, interval '1 month') dates (d)
GROUP BY dt;  --<< the group by is necessary

也许可以加快查询速度。

您还可以尝试将日期生成放入CTE:

with dates (d) as (
  SELECT t::date
  from generate_series('2012-01-01'::date, '2016-12-01'::date, interval '1 month') t
)
SELECT dt, SUM(value)
FROM example
WHERE dt IN ( select d from dates)
GROUP BY dt;

有时候做JOIN也会更有效率:

with dates (d) as (
  SELECT t::date
  from generate_series('2012-01-01'::date, '2016-12-01'::date, interval '1 month') t
)
SELECT dt, SUM(value)
FROM example
  JOIN dates on example.dt = dates.d
GROUP BY dt;

答案 1 :(得分:0)

您的查询中的性能问题来自于您生成每日系列的事实。将其更改为每月,移除distinct并添加group by

select dt, sum(value)
from
    example
    inner join (
       select date_trunc('month', dt) + interval '1 month - 1 day' as dt
       from generate_series('2012-01-01'::date, '2016-12-01', '1 month') gs (dt)
    ) d using (dt)
group by dt