2011-12-19 7 views
0

Ruby 1.9.2、Rails 3.1を使用します。私は、次のコードをしている:Railsでこのメソッドをリファクタリングして、SQLクエリが2回実行されないようにします。

# 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を合計するために使用されるのに対し、評価の数の合計数が、返さ取得するために使用されます。結果を達成するために、クエリが複数回実行されることに気付きました。

これをリファクタリングしてパフォーマンスを向上させる方法はありますか?

ありがとうございました。あなたは平均的な機能が存在しなかった場合、あなたは可能性たとえば、カスタムSQL記述する必要があるかもしれないより一般的に

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

を行うことができるはずので

答えて

1

アクティブレコードAPIは、SQL平均機能を公開しますあなたは

select count(*) as number_of_ratings, SUM(IF(rating > 5, 1, 0)) as number_of_ratings_greater_than_5, SUM(rating) as total_score 
のようなものを使用することができる条件のセットが異なる複数のものをカウントしたい場合

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

書きます

を取得するには、1つのクエリで評価の数、その合計、および評価の数> 5を取得します。 2つの高速クエリを1つの非常に低速なクエリに置き換えることは慎重にしてください。検討可能と仮定

+0

OMG、私がすることはできません最初のSQLステートメントでもっと感謝しています! – Victor

1

は、多くのレビューがあります:あなたのDBは、構文をサポートしている場合

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

または1つのショットでは、[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

関連する問題