2012-08-22 21 views
0

全部都是,日志中的未知SQL平均查询Rails

我刚刚对SQL平均查询有个疑问。

我有一个帖子模型,它有很多评级。某个特定帖子的所有评分都加起来,并除以平均评分数。所以这个计算是在后期模型中声明并保存在数据库中。在我的索引视图中,我列出了所有帖子,其作者,姓名和评分均来自帖子评分数据库列。

我的问题是,为什么rails在这些值已被保存在数据库中时执行所有这些SQL平均查询?

我的代码如下:

在控制台

Post Load (1.0ms) SELECT `posts`.* FROM `posts` ORDER BY posts.created_at ASC LIMIT 1 
=> #<Post id: 48, user_id: 5, song_name: "Enter Sandman", song: "ewwe wer ere rr erew rewr r erw erw rewedwde", created_at: "2012-08-16 13:35:32", updated_at: "2012-08-22 21:11:34", rating: 5.0, ratings_count: 2> 

Post.rb

def rating 
    if self.ratings.any? 
     self.rating = self.ratings.average(:rating) 
    end 
    end 

帖子/ index.html.erb

<legend>Music library</legend> 

    <%= will_paginate @paginate_posts %> 

      <% if @paginate_posts.any? %> 
       <% @paginate_posts.each do |post| %> 
      <h4><%= link_to post.song_name, post %></h4> 
       Author: <%= link_to post.user.name, "#" %><br/> 
        <% if post.rating == nil %> 
         No one has rated this yet<br/> 
        <% else %> 
         Rating: <%= post.rating %>/10<br/> 
        <% end %> 
       <br/> 
     <% end %> 
<% end %> 

<%= will_paginate @paginate_posts %> 

posts_controller。 RB指数行动(我有三编预先加载,但平均疑问仍然存在)

def index 
    @paginate_posts = Post.paginate(page: params[:page], per_page: 10).includes(:user).search(params[:search]) 
    end 

SQL日志,有很多查询

Started GET "/" for 127.0.0.1 at 2012-08-22 22:51:38 +0100 
Processing by PostsController#index as HTML 
    Post Load (0.3ms) SELECT `posts`.* FROM `posts` ORDER BY posts.created_at DESC LIMIT 10 OFFSET 0 
    User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` IN (5) 
    (0.3ms) SELECT COUNT(*) FROM `posts` 
    Rendered posts/_copy.html.erb (0.1ms) 
    (0.3ms) SELECT AVG(`ratings`.`rating`) AS avg_id FROM `ratings` WHERE `ratings`.`post_id` = 63 
    CACHE (0.0ms) SELECT AVG(`ratings`.`rating`) AS avg_id FROM `ratings` WHERE `ratings`.`post_id` = 63 
    (0.3ms) SELECT AVG(`ratings`.`rating`) AS avg_id FROM `ratings` WHERE `ratings`.`post_id` = 62 
    CACHE (0.0ms) SELECT AVG(`ratings`.`rating`) AS avg_id FROM `ratings` WHERE `ratings`.`post_id` = 62 
    (0.2ms) SELECT AVG(`ratings`.`rating`) AS avg_id FROM `ratings` WHERE `ratings`.`post_id` = 61 
    CACHE (0.0ms) SELECT AVG(`ratings`.`rating`) AS avg_id FROM `ratings` WHERE `ratings`.`post_id` = 61 
    (0.2ms) SELECT AVG(`ratings`.`rating`) AS avg_id FROM `ratings` WHERE `ratings`.`post_id` = 60 
    CACHE (0.0ms) SELECT AVG(`ratings`.`rating`) AS avg_id FROM `ratings` WHERE `ratings`.`post_id` = 60 
    (0.2ms) SELECT AVG(`ratings`.`rating`) AS avg_id FROM `ratings` WHERE `ratings`.`post_id` = 59 
    CACHE (0.0ms) SELECT AVG(`ratings`.`rating`) AS avg_id FROM `ratings` WHERE `ratings`.`post_id` = 59 
    (0.2ms) SELECT AVG(`ratings`.`rating`) AS avg_id FROM `ratings` WHERE `ratings`.`post_id` = 58 
    CACHE (0.0ms) SELECT AVG(`ratings`.`rating`) AS avg_id FROM `ratings` WHERE `ratings`.`post_id` = 58 
    (0.2ms) SELECT AVG(`ratings`.`rating`) AS avg_id FROM `ratings` WHERE `ratings`.`post_id` = 57 
    CACHE (0.0ms) SELECT AVG(`ratings`.`rating`) AS avg_id FROM `ratings` WHERE `ratings`.`post_id` = 57 
    (0.2ms) SELECT AVG(`ratings`.`rating`) AS avg_id FROM `ratings` WHERE `ratings`.`post_id` = 56 
    CACHE (0.0ms) SELECT AVG(`ratings`.`rating`) AS avg_id FROM `ratings` WHERE `ratings`.`post_id` = 56 
    (0.2ms) SELECT AVG(`ratings`.`rating`) AS avg_id FROM `ratings` WHERE `ratings`.`post_id` = 55 
    CACHE (0.0ms) SELECT AVG(`ratings`.`rating`) AS avg_id FROM `ratings` WHERE `ratings`.`post_id` = 55 
    (0.3ms) SELECT AVG(`ratings`.`rating`) AS avg_id FROM `ratings` WHERE `ratings`.`post_id` = 54 
    CACHE (0.0ms) SELECT AVG(`ratings`.`rating`) AS avg_id FROM `ratings` WHERE `ratings`.`post_id` = 54 
    Rendered posts/index.html.erb within layouts/application (60.8ms) 
    User Load (0.4ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 5 LIMIT 1 
    Rendered layouts/_footer.html.erb (0.1ms) 
Completed 200 OK in 2012ms (Views: 1871.7ms | ActiveRecord: 33.1ms) 

像往常一样,如果你需要更多的代码就骂。 非常感谢,安迪

+1

是什么让你认为“这些值已经保存在数据库中”是真的? –

+0

嗯,很好的一点,Ive在检索帖子时更新了我的答案和来自控制台的信息。它似乎将评分保存为5.0?情况并非如此? – dodgerogers747

回答

2

你有一个称为评价的方法,这个方法在你的模型中覆盖了访问器,所以即使你有一个db列'评级',当你询问model.rating时也不会被调用,这个方法将会再次重复评级。此外,该方法不保存(只需设置一个属性不会保留到数据库,您需要调用保存或类似)。所以如果你想把价值保存在评价中,我会摆脱这种方法。

你应该真的这样做时,该职位添加了评分或更改 - 在这一点上,调用update_rating或什么(见下文),然后确保你打电话post.save之后(使之成为before_save回调,或致电self.update_attribute或self.save explitly在update_rating) - 将更改保存到数据库,然后你就可以在视图中使用

<%= post.rating %> 

或其他地方作为缓存的平均评分值。

在Post模型:

before_save :update_rating 

def update_rating 
    if self.ratings.any? 
    self.rating = self.ratings.average(:rating) 
    end 
end 
+0

嗨肯尼,我不知道一个方法名称可能会覆盖模型中的访问器,太棒了!谢谢!安迪 – dodgerogers747

1

您的循环在您的文章。在每个循环中,您拨打:

post.rating 

这在您的AVG SQL查询的转火:

self.ratings.average(:rating) 

它不会被保存,它只是计算让你 '如果post.rating =' 工作

+0

嗨Rogier,我已经完成了一些事情,但总体上不知道如何正确解决这个问题,我怎么能把这个保存到数据库?非常感谢 – dodgerogers747

+0

你为什么要保存它?我可以想象,评级正在变化(即更多的职位),所以self.ratings.平均(:评级)给你总是最新的(和最准确的)评级。 – Roger

+0

我想保存平均值,以便当我遍历帖子以获得他们的评级时,它不执行及时的sql查询负载,现在可以确定,因为没有很多歌曲,但是当有几百个歌曲时会有点痛苦。 – dodgerogers747

1

根据我的经验,我发现,@肯尼 - 格兰特的update_rating方法实际上并不包括新计算并持续更新的等级增加时的平均收视率。在这个阶段

after_save :update_rating! 

def update_rating 
    self.rating = ratings.average(:rating) || 0.0 
end 

def update_rating! 
    self.update_columns(rating: update_score) 
end 

这确保了新添加的记录显示,自ratings是到数据库的调用,而不是在内存:

这很适合我。 update_columns可让您重写记录,而不会导致触发其所有回叫的额外动作save。在写入列时使用update_rating方法还会设置内存中评级属性,除非您之后还重新加载了模型,否则update_columns将不会执行此操作。