当计数的数量级为100,000 - 10,000,000时,获取两次之间发生事件的次数。
列:
获取计数的查询(伪代码):
COUNT rows WHERE time_occurred > <begin_time> AND time_occurred < <end_time>
这样可行,但查询效率很低,大约需要40秒才能响应。据我了解,PostgreSQL不适合用于此类查询。
我坐下来想了几种方法,可以在O(log n)时间内索引和执行这种类型的查询,所以我知道这是可能的。
我应该使用哪些工具来执行此操作?我们应该使用不同的数据库来存储计数行吗?我们可以在PostgreSQL上安装一个包来轻松完成吗?我们有什么选择?
不确定我是否清楚这一点。 COUNT
的结果应为100,000 - 10,000,000。这意味着与查询匹配的行数将为100,000 - 10,000,000。表中的实际行数要多一个数量级。
非常感谢!
答案 0 :(得分:5)
Pre-PostgreSQL 9.2 MVCC的实现需要任何查询来访问表的每一行,以检查该行的版本是否对当前事务可见。即使查询仅涉及索引列,也会发生这种情况。这表现为大表的计数缓慢,即使对于简单的情况也是如此。
PostgreSQL 9.2实现了index only scans,这可能有助于缓解某些工作负载的这个问题。
如果您被困在v9.2以下,如果您只需要对简单查询进行近似行计数,则有一些已知的解决方法。请参阅http://wiki.postgresql.org/wiki/Count_estimate。
答案 1 :(得分:1)
按日汇总事件表。
create table incidents_agreggated_by_day (
"day" date primary key, total integer
);
日常运行:
insert into events_agreggated_by_day ("day", total) values
select date_trunc('day', time_occurred), count(*) total
from incidents
where
time_occurred < current_date
and date_trunc('day', time_occurred) not in (
select "day" from incidents_agreggated_by_day
)
group by 1
假设您想要“2013-01-01 10:37”和“2013-03-02 11:20”之间的总数:
select
(
select sum(total)
from incidents_aggregated_by_day
where "day" >= '2013-01-02'::date and "day" < '2013-03-02'::date
) +
(
select count(*)
from incidents
where
time_ocurred >= '2013-01-01 10:37':timestamp
and time_ocurred < '2013-01-02'
or
time_ocurred <= '2013-03-02 11:20':timestamp
and time_ocurred >= '2013-01-02'
) total
您不会阅读1亿行,而是阅读数百或数千行。如果正确索引,它将会很快。
答案 2 :(得分:1)
另一种方法可能是对表进行分区。这家伙似乎解决了一个非常类似的分区问题:
我对使用他的方法的关注是可维护性。在他的示例中(您必须单击本教程的第1部分以了解他是如何创建分区的),他手动创建每个子表并在触发器中对子表进行硬编码路由。如果你的桌子不断增长,你将会做很多DBA的工作。
然而,他似乎确实获得了巨大的性能提升。所以,如果你能弄清楚如何使它更易于维护,这可能是一个很好的方法。
答案 3 :(得分:1)
这正是维度建模和数据仓库旨在解决的问题。
我之前的一个项目是在几周内在Ruby中构建了一个数据仓库,以便处理这样的查询,并使用简单的REST API将其公开给主应用程序。基本上,您提取数据并将其转换为“星型模式”,该模式针对您描述的查询进行了高度优化。
Postgresql非常适合作为数据仓库数据库。
这是一个非常详细的主题,这是一个很好的入门资源:http://www.amazon.com/Data-Warehouse-Toolkit-Complete-Dimensional/dp/0471200247