5

我正在使用Rails和MySQL,并且有一个基于行计数的效率问题。我有一个Project型号has_many :donations正在存储数据库记录的冗余?

我想统计一个项目的唯一捐助者数量。

projects表中有一个名为num_donors的字段,并且在创建新捐助者时递增该字段是一个好主意?

或者像@num_donors = Donor.count(:select => 'DISTINCT user_id')这样的东西在效率方面会因为数据库优化而变得相似或相同?这是否需要我为user_id和我想要计数的其他字段创建索引?

相同的答案持有总和捐赠总额?

回答

10

要回答标题问题。是的,这是多余的,但你是否应该这样做取决于你的情况。

除非您知道性能问题,否则请在您的应用程序中即时计算计数和总计,并且不要存储它们。也就是说,除非没有其他选择,否则不要存储计算的值。

在大多数情况下,你不必诉诸于此,不应该。

如果您必须存储计算值,请执行下列操作:

  • 不要通过递增它跟上最新的。每次更新时重新计算所有数据的计数/总数。
  • 如果您没有太多更新, 会将代码更新触发器更新为 ,使计数/总数保持最新。
  • 数据库的冗余问题在于当数字 不同意时,您不确定哪个是权威性的 。添加到 文档的注意事项来源 数据是权威的来源,如果 他们不同意并且可以被覆盖。
7

虽然这取决于数据库的大小,但这些是数据库专用的操作类型,所以它们应该很快。这可能是过早优化的情况 - 您应该首先不存储总计,从而使其更简单 - 如果需要,可以稍后进行优化。

4

彼得和JohnFx的答案是健全的,你要建议的是你的数据库架构的denormalization,它可以提高读取性能,但在写,而另外把责任推给开发商​​(或其他DBMS clevers的损害)以防止数据集内的不一致。

ActiveRecord具有一些内置的功能,可以自动管理has_many关系的计数。看看这个Railscast on counter caches

5

记住格言“有一只手表的男人总是知道时间,一个有两只手表的男人永远不会确定。“我只会在以下情况下存储派生的数字:

性能问题会阻止您在需要时获取派生数字(在这种情况下这应该不是问题,因为答案很可能来自索引)

你有理由相信,你是从通过编程错误或有意或无意的用户操作主表中丢失的纪录。在这种情况下,您可以使用您的派生号审计当前计算的数。

+0

爱的格言 - 以前没听过。请记住:) – nfm 2009-10-03 03:13:37

3

你知道吗一个简单的国旗做ActiveRecord魔术?

class ThingOwner 

# it has a column like 
# t.integer things_count, :default => 0 

has_many :things, :counter_cache => true 

end 

至于这个问题 - 是的,当然它是多余的,我想补充这样一个计数器,当且仅如果时间things.count的份额过大。

否则,它是过早的优化。