2015-12-09 3 views
1

У меня есть таблица, содержащая столбец timestamp и столбец sourcevarchar(20). Я вставляю пару тысяч записей в эту таблицу каждый час, и я хотел бы показать совокупность этих данных. Мой запрос выглядит следующим образом:Агрегатный запрос PostgreSQL очень медленный

EXPLAIN (analyze, buffers) SELECT 
    count(*) AS count 
FROM frontend_car c 
WHERE date_created at time zone 'cet' > now() at time zone 'cet' - interval '1 week' 
GROUP BY source, date_trunc('hour', c.date_created at time zone 'CET') 
ORDER BY source ASC, date_trunc('hour', c.date_created at time zone 'CET') DESC 

Я уже создал индекс, как так:

create index source_date_created on 
table_name(
    (date_created AT TIME ZONE 'CET') DESC, 
    source ASC, 
    date_trunc('hour', date_created at time zone 'CET') DESC 
); 

И выход из моих ANALYZE является:

QUERY PLAN 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
Sort (cost=142888.08..142889.32 rows=495 width=16) (actual time=10242.141..10242.188 rows=494 loops=1) 
    Sort Key: source, (date_trunc('hour'::text, timezone('CET'::text, date_created))) 
    Sort Method: quicksort Memory: 63kB 
    Buffers: shared hit=27575 read=28482 
    -> HashAggregate (cost=142858.50..142865.93 rows=495 width=16) (actual time=10236.393..10236.516 rows=494 loops=1) 
     Group Key: source, date_trunc('hour'::text, timezone('CET'::text, date_created)) 
     Buffers: shared hit=27575 read=28482 
     -> Bitmap Heap Scan on frontend_car c (cost=7654.61..141002.20 rows=247507 width=16) (actual time=427.894..10122.438 rows=249056 loops=1) 
       Recheck Cond: (timezone('cet'::text, date_created) > (timezone('cet'::text, now()) - '7 days'::interval)) 
       Rows Removed by Index Recheck: 141143 
       Heap Blocks: exact=27878 lossy=26713 
       Buffers: shared hit=27575 read=28482 
       -> Bitmap Index Scan on frontend_car_source_date_created (cost=0.00..7592.74 rows=247507 width=0) (actual time=420.415..420.415 rows=249056 loops=1) 
        Index Cond: (timezone('cet'::text, date_created) > (timezone('cet'::text, now()) - '7 days'::interval)) 
        Buffers: shared hit=3 read=1463 
Planning time: 2.430 ms 
Execution time: 10242.379 ms 
(17 rows) 

Очевидно, что это слишком медленно и на мой взгляд, он должен быть способен вычисляться только с использованием индексов, если я использую только время или источник для агрегации, это достаточно быстро, но вместе как-то медленно.

Это довольно небольшой VPS с 512 МБ оперативной памяти, а база данных в настоящее время содержит около 700 тыс. Строк.

Из того, что я читал, кажется, что большая часть времени тратится на перепроверку, а это значит, что индекс не поместился в память?

+0

Какая у вас настройка 'work_mem' для этого запроса? Можете ли вы увеличить его и перепроверить? – vyegorov

+0

Его по умолчанию 4 МБ, я пытался увеличить до 300 МБ, но безуспешно. – mirosval

+0

Как «Кучи блоков: точное = 27878 lossy = 26713' и' Строки, удаленные с помощью индекса «Повторная проверка индекса»: строки меняются с увеличением 'work_mem'? Я думаю, что, возможно, частичный индекс в вашем предложении 'WHERE' может помочь лучше. – vyegorov

ответ

1

Похоже, что вам действительно нужна отдельная таблица агрегатов, которая получает записи, вставленные или обновленные с помощью триггера в вашей подробной таблице. Сводная таблица будет иметь ваш столбец источника, поле даты/времени, чтобы удерживать только часть даты и часа (обрезание в считанные минуты) и, наконец, счетчик выполнения.

По мере добавления записей эта сводная таблица обновляется, тогда ваш запрос может быть непосредственно в этой таблице. Поскольку он уже будет предварительно агрегирован по источнику, дате и часу, ваш запрос просто должен будет применить предложение where и порядок, который будет указан источником.

Я не свободно говорю с postgresql, но уверен, что у них есть свои собственные триггеры вставки. Итак, если у вас 1000 единиц записей каждый час, и вы говорите, что у вас 10 источников. Весь ваш итоговый набор этой сводной сводной таблицы будет всего 24 (час) * ex 50 (источники) = 1200 записей в день против 50k, 60k, 70k + в день. Если вам нужны точные данные за определенную дату/час, вы можете затем развернуть детали по мере необходимости. Но на самом деле, сколько «источников» вы имеете дело с неясно.

Я бы очень признал это как решение ваших потребностей.

+0

Да, я надеялся избежать этого, так как я думал, что это может быть достигнуто только через подсчет индексов, но, видимо, этого не происходит. Я потратил около 3-4 полных дней на то, чтобы попробовать все, что мог, прочитав руководство PostgreSQL и не смог найти ничего лучшего. – mirosval

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