我正在使用Rails和MySQL,并且有一个基于行计数的效率问题。
我有一个Project
模型has_many :donations
。
我想计算一个项目的独特捐赠者数量。
在projects
表格中有一个名为num_donors
的字段,并在创建新捐赠者时将其递增是一个好主意吗?
或者,由于数据库优化,@num_donors = Donor.count(:select => 'DISTINCT user_id')
在效率方面类似或相同?这是否需要我为user_id
和我想要计算的任何其他字段创建索引?
对于捐赠总额的总结,是否有同样的答案?
答案 0 :(得分:10)
回答标题问题。是的,它是多余的,但你是否应该这样做取决于你的情况。
除非您知道性能问题,否则请在应用程序中动态计算计数和总计,不要存储它们。也就是说,除非您没有其他选择,否则不要存储计算值。
在大多数情况下,你不必诉诸于此而不应该这样做。
如果必须存储计算值,请执行以下操作:
答案 1 :(得分:7)
虽然它取决于数据库的大小,但这些是数据库专用的操作类型,因此它们应该很快。这可能是一个过早优化的情况 - 你应该首先不存储总数,从而使其更简单 - 并在必要时进行优化。
答案 2 :(得分:5)
记住格言“有一只手表的男人总是知道时间。有两只手表的男人永远不会确定。”我只会存储派生的数字:
性能问题阻止您在需要时获取派生数字(在这种情况下这不应该是一个问题,因为答案很可能从索引中获得)
或
您有理由相信您通过程序员错误或故意或意外的用户操作丢失了主表中的记录。在这种情况下,您可以使用派生的数字来审核当前计算的数字。
答案 3 :(得分:4)
Peter和JohnFx的答案是合理的,你提出的是你的数据库模式的denormalization,这可以提高读取性能但是在不利于写入的同时还要将责任放在开发人员(或其他DBMS)上聪明)以防止数据集中的不一致。
ActiveRecord具有一些内置功能,可以自动管理has_many
关系上的计数。看看这个Railscast on counter caches。
答案 4 :(得分:3)
你知道ActiveRecord魔法有一个简单的标志吗?
class ThingOwner
# it has a column like
# t.integer things_count, :default => 0
has_many :things, :counter_cache => true
end
至于问题 - 是的,确定它是多余的,如果things.count
的时间份额过大,我会添加这样一个计数器,而仅。
否则就是过早优化。