PostgreSQL:count()还是保留一个计数器?

时间:2013-02-21 08:25:46

标签: sql postgresql

我有两个一对多关系的表。假设对于表foo中的每一行,表bar中可以有0行或更多行引用foo中的行。

客户想知道barfoo中有多少行引用fooSELECT count(bar_id) FROM bar WHERE bar.foo_id = foo.foo_id; 中所有行的行。

我可以通过以下查询来完成此任务:

foo

但是,如果表barfoo很大,怎么办?说bar有100万行,foo有1000万行。我们还要说bar中99%的行的引用次数少于1,000 foo行。假设客户端通常一次要求大约100行bar

我应该使用带有外键索引的naive count()查询,还是保留计数器会更好?甚至可以保留一个柜台?通过使用{{1}}上的触发器以原子增量和减量更新计数器,我相信这是可能的,但我可能是错的。

2 个答案:

答案 0 :(得分:5)

也许与直觉相反,您可能会发现简单的count方法更快,除非您的工作量偏向于读取。

这样做的原因是计数器表的效果将是序列化更新,因此在任何给定时间只有一个更新给定foo的事务可以在飞行中。那是因为更新计数器的触发器的更新将锁定计数器表中的foo条目,并且在事务回滚或提交之前不会释放它。

更糟糕的是,如果您的交易影响多个foo,另一个交易会影响另一个,那么由于死锁,其中一个交易很可能会中止。

坚持一个简单的计数,直到你有充分的理由改变它。

答案 1 :(得分:3)

关于索引的甜蜜之处在于它们为查询操作提供了对数的复杂性。因此,对于10*10^6行,索引只需要ln(10*10^6)=16.1个比较来查找一个特定的id。使其成为1亿行,您只需要进行2到3次比较。简而言之:索引并不太关心表的大小。

当然,您仍然可以使用存储的计数器存档一些性能提升。这是一个典型的权衡。维护计数器会使bar的插入和删除更加昂贵,并使您的计数查询更便宜一些。

因此,如果您的表很少被更改并且查询经常运行(例如,每小时数千次),您可能会使用存储的计数器过程获得性能。但是,在大多数情况下,我会说索引列,让数据库为您完成剩下的工作。