我有以下模型,允许用户在照片上投票。
class Vote < ActiveRecord::Base
attr_accessible :value
belongs_to :photo
belongs_to :user
validates_associated :photo, :user
validates_uniqueness_of :user_id, :scope => :photo_id
validates_uniqueness_of :photo_id, :scope => :user_id
validates_inclusion_of :value, :in => [-2,-1,1,2], :allow_nil => true
after_save :write_photo_data
def self.score
dd = where( :value => -2 ).count
d = where( :value => -1 ).count
u = where( :value => 1 ).count
uu = where( :value => 2 ).count
self.compute_score(dd,d,u,uu)
end
def self.compute_score(dd, d, u, uu)
tot = [dd,d,u,uu].sum.to_f
score = [-5*dd, -2*d, 2*u, 5*uu].sum / [tot,4].sum*20.0
score.round(2)
end
private
def write_photo_data
self.photo.score = self.photo.votes.score
self.photo.save!
end
end
这个功能非常好,但计算照片的分数非常慢 - 平均需要7-12秒。我已经尝试为photo_id
,user_id
添加索引,并为photo_id
和value
添加一个索引,但就我所知,这并没有真正改善性能
我对任何严肃的铁路专家(我完全是业余爱好者)的反馈感兴趣,以了解如何优化/改进。你如何计算特定照片和价值的投票?
谢谢!
- 编辑 -
请注意,得分:-2,-1,1,2
代表“双拇指向下,单拇指向下,拇指向上,双拇指向上”,而非特定值。我可以将这些与我在计算分数方法中分配给它们的值相匹配,但到目前为止我还没有这样做,因为我可能希望在看到更多数据累积后随时调整权重。
此外,无论我如何在数据库中代表这四种可能的投票,我仍然需要每种投票的COUNT以及每张照片的加权值来计算得分。谢谢!
答案 0 :(得分:1)
您可以做的一件事就是要求数据库一次而不是四次获得分数:
Vote.where(photo_id: photo.id).group(:value).count
会导致单个数据库查询并为您提供类似
的哈希值{-2 => 21, -1 => 48, 1 => 103, 2 => 84}
除此之外,如果您在数据库中存储[-5, -2, 2, 5]
而不是[-2, -1, 1, 2]
的实际值,您可以这样做
Vote.where(photo_id: photo.id).sum
直接从数据库中获取总和(或者甚至使用avg
来获得平均值)
答案 1 :(得分:1)
您需要一个值索引。组合索引仅在查询具有两个组件时起作用,从左侧开始。由于您的where子句未指定照片ID,因此它不使用您的组合索引。
更新请参阅http://dev.mysql.com/doc/refman/5.0/en/multiple-column-indexes.html
答案 2 :(得分:0)
为什么要存储-2,2,1,2而不是实际等级?如果存储成绩(例如-5),您将能够直接在DB中计算得分而无需运行4个计数查询。这肯定会有所改善。
答案 3 :(得分:0)
如果数据库中有大量记录,则在值列上添加索引将加快SELECT。
上述帖子也提出了直接优化的一些优点。但是,随着您的数据库扩展,所有这些方法最终都会失败。由于分数是派生值,您可以将其缓存在Memcached,Redis甚至SQL中,这将确保在应用程序增长时获取分数在固定时间内进行缩放。您可以允许缓存过时并使用后台进程更新缓存。通过这样做,您的计算功能可以任意长,而不会影响用户体验。