计算高幅度计数(100,000+)的匹配行数

时间:2013-03-10 02:24:22

标签: sql postgresql count nosql counter

目的:

当计数的数量级为100,000 - 10,000,000时,获取两次之间发生事件的次数。

当前实施:

  • 使用PostgreSQL
  • 每个“事件”都记录为表格中的单独行

列:

  • 事件类型
  • 日期 - 发生的时间

获取计数的查询(伪代码):

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。表中的实际行数要多一个数量级。

非常感谢!

4 个答案:

答案 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)

另一种方法可能是对表进行分区。这家伙似乎解决了一个非常类似的分区问题:

http://www.if-not-true-then-false.com/2009/performance-testing-between-partitioned-and-non-partitioned-postgresql-tables-part-3/

我对使用他的方法的关注是可维护性。在他的示例中(您必须单击本教程的第1部分以了解他是如何创建分区的),他手动创建每个子表并在触发器中对子表进行硬编码路由。如果你的桌子不断增长,你将会做很多DBA的工作。

然而,他似乎确实获得了巨大的性能提升。所以,如果你能弄清楚如何使它更易于维护,这可能是一个很好的方法。

答案 3 :(得分:1)

这正是维度建模和数据仓库旨在解决的问题。

我之前的一个项目是在几周内在Ruby中构建了一个数据仓库,以便处理这样的查询,并使用简单的REST API将其公开给主应用程序。基本上,您提取数据并将其转换为“星型模式”,该模式针对您描述的查询进行了高度优化。

Postgresql非常适合作为数据仓库数据库。

这是一个非常详细的主题,这是一个很好的入门资源:http://www.amazon.com/Data-Warehouse-Toolkit-Complete-Dimensional/dp/0471200247