4

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

客户想知道 中的所有行在 中bar引用了多少行。foofoo

我可以通过以下查询完成此操作:

SELECT count(bar_id) FROM bar WHERE bar.foo_id = foo.foo_id;

foo但是,如果桌子bar很大怎么办?Sayfoo有 100 万行,并且bar有 1000 万行。假设 99% 的行引用它的行foo数少于 1,000行。bar假设客户通常foo一次要求大约 100 行。

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

4

2 回答 2

5

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

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

更糟糕的是,如果您的事务影响多个事务foo并且另一个事务也影响,那么您很有可能由于死锁而中止其中一个事务。

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

于 2013-02-21T08:38:54.563 回答
4

索引的好处在于它们为查询操作提供了对数复杂度。因此,对于10*10^6行,索引只需要ln(10*10^6)=16.1进行比较即可找到一个特定的 id。让它有 1 亿行,你只需要多做 2 到 3 次比较。简而言之:索引并不太关心表的大小。

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

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

于 2013-02-21T08:38:25.063 回答