2016-11-09 3 views
1

Я хочу запросить таблицу и суммировать столбец для всех строк с последнего дня месяца.Postgres - быстрый способ суммирования по строкам с последнего дня месяца

Давайте использовать следующую таблицу в качестве примера:

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 и сделать это так же быстро, как и последняя версия?

ответ

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 

Возможно, это ускоряет запрос.

Вы также можете попробовать поставить поколение даты в КТР:

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; 

Иногда делает РЕГИСТРИРУЙТЕСЬ также более эффективно:

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; 
+0

Вот запрос я использовал: 'ВЫБРАТЬ дт, SUM (значение) из примера WHERE дт в (выберите date_trunc («месяц», d) + интервал '1 месяц - 1 день' from generate_series ('2012-01-01' :: date, '2016-11-10' :: date, interval '1 month') date (d)) ' –

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 
Смежные вопросы