【问题标题】:Refactor this method in Rails to prevent SQL query from running twice在 Rails 中重构此方法以防止 SQL 查询运行两次
【发布时间】:2011-12-20 02:06:33
【问题描述】:

使用 Ruby 1.9.2、Rails 3.1。我有以下代码:

# review.rb
def calculate_rating(reviewable)
  total_rating = Review.select("rating").where(:reviewable_id => self.reviewable_id)
  sum_rating = total_rating.sum(:rating)
  new_rating_average = sum_rating.to_f / total_rating.size
  reviewable.update_attribute(:rating_average, new_rating_average)
end

total_rating 实际上用于获取返回的评分总数,而sum_rating 用于对每个total_rating 求和。我注意到我的查询运行了多次以获得结果。

有没有办法重构它以提高性能?

谢谢。

【问题讨论】:

    标签: ruby ruby-on-rails-3


    【解决方案1】:

    活动记录api公开了SQL平均功能,所以你应该可以做到

    average_rating = Review.where(:reviewable_id => self.reviewable_id).average(:rating)
    

    一般情况下你可能需要编写自定义sql,例如如果不存在平均函数,你可以编写

    select count(*) as c, sum(rating) as total from ratings where ( ... )
    

    如果您想计算具有不同条件的多个事物,您可以使用类似

    select count(*) as number_of_ratings, SUM(IF(rating > 5, 1, 0)) as number_of_ratings_greater_than_5, SUM(rating) as total_score
    

    要获得,在 1 中查询评分数、它们的总和以及评分数 > 5。 但是请谨慎使用,您不想用一个非常慢的查询替换 2 个快速查询!。

    【讨论】:

      【解决方案2】:

      假设 reviewable 有很多评论:

      reviewable.update_attribute :rating_average, reviewable.reviews.average(:rating)
      

      或者,如果您的数据库支持语法 [1]

      Reviewable.connection.execute <<-eos
        UPDATE reviewable SET (rating_average) = ((
          SELECT avg(rating) FROM review WHERE reviewable_id = {reviewable_id}
        )) where id = {reviewable_id}
      eos
      

      [1]http://publib.boulder.ibm.com/infocenter/idshelp/v10/index.jsp?topic=/com.ibm.sqls.doc/sqls875.htm

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-18
        • 2023-01-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多