PostgreSQL聚合查询非常慢

时间:2015-12-09 21:03:16

标签: sql postgresql aggregate postgresql-performance

我有一个表格,其中包含timestamp列和sourcevarchar(20)。我每小时在这个表中插入几千个条目,我想显示这个数据的汇总。我的查询如下:

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,只有512MB的ram,数据库目前包含大约700k行。

从我读到的内容看来,大部分时间花在重新检查上,这意味着索引不适合内存?

1 个答案:

答案 0 :(得分:2)

听起来你真正需要的是一个单独的聚合表,它通过详细表格中的触发器插入或更新记录。摘要表将包含您的源列,日期/时间字段仅包含日期和小时部分(截断任何分钟),最后是运行计数。

在插入记录时,此摘要表会更新,然后您的查询可以直接在此表上。由于它已经按来源,日期和小时预先汇总,因此您的查询只需要应用where子句并按来源对其进行排序。

我对postgresql一点也不流利,但我确信他们有自己的插入触发器方法。所以,如果你每小时有1000个条目,并说你有10个来源。此汇总汇总表的整个结果集仅为24(小时)*前50(来源)=每天1200条记录,而每天为50k,60k,70k +。如果您需要每个给定日期/小时的确切详细信息,则可以根据需要深入了解详细信息。但实际上,有多少"来源"你在处理的是不清楚的。

我强烈认为这是解决您需求的方法。