9

我正在使用 Rails 和 MySQL,并且有一个基于行计数的效率问题。

我有一个Project模型has_many :donations

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

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

或者@num_donors = Donor.count(:select => 'DISTINCT user_id')由于数据库优化,在效率方面是否会变得相似或相同?这是否需要我为user_id我想要计算的任何其他字段创建索引?

对捐赠的总金额求和是否同样的答案?

4

5 回答 5

17

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

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

在大多数情况下,您不必诉诸于此,也不应该这样做。

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

  • 不要通过增加它来保持它是最新的。每次更新时重新计算所有数据的计数/总数。
  • 如果您没有很多更新,请将代码放在更新触发器中以保持计数/总数最新。
  • 数据库冗余的问题在于,当数字不一致时,您不确定哪个是权威的。在文档中添加注释,如果源数据不同意并且可以被覆盖,则源数据是权威来源。
于 2009-10-03T00:39:33.717 回答
9

虽然这取决于数据库的大小,但这些是数据库专门从事的操作类型,因此它们应该很快。这可能是过早优化的情况 - 您应该从不存储总数开始,从而使其更简单 - 并在必要时稍后进行优化。

于 2009-10-03T00:32:22.690 回答
7

记住一句格言:“一个人带着一块表,永远知道时间。一个带着两块表的人,永远不确定。” 我只会在以下情况下存储派生数字:

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

或者

您有理由相信由于程序员错误或故意或意外的用户操作正在丢失主表中的记录。在这种情况下,您可以使用派生数字来审核当前计算的数字。

于 2009-10-03T02:46:15.243 回答
5

Peter 和 JohnFx 的答案是合理的,您提出的是数据库模式的非规范化,这可以提高读取性能,但会损害写入,同时还要让开发人员(或其他 DBMS 聪明人)承担责任,以防止您的内部出现不一致数据集。

ActiveRecord 有一些内置功能可以自动管理has_many关系计数。看看这个关于计数器缓存的 Railscast

于 2009-10-03T02:28:41.080 回答
3

你知道 ActiveRecord 魔术的简单标志吗?

class ThingOwner

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

has_many :things, :counter_cache => true

end

至于问题 - 是的,肯定它是多余的,当且仅things.count' 的时间份额太大时,我才会添加这样一个计数器。

否则就是过早的优化。

于 2009-10-03T07:24:22.890 回答