Rails 3和memcaching关联

时间:2012-11-09 14:10:14

标签: ruby-on-rails-3 memcached associations

Following.rb

belongs_to :show

def cached_show
  Rails.cache.fetch([self, :show]) do
    show      
  end
end

查看:

<% @recently_favorited.each do |following| %>
<li>
  <%= link_to "#{following.cached_show.name}", show_path(:permalink => following.cached_show.permalink) %> <span><%= "(#{pluralize(following.cached_show.followers, "follower")})" %></span>
</li>
<% end %>

控制台中的结果:

Cache read: followings/632770-20120929132253/show
Cache generate: followings/632770-20120929132253/show
  Show Load (0.7ms) SELECT `shows`.* FROM `shows`WHERE `shows`.`id` = 617 LIMIT 1
Cache write: followings/632770-20120929132253/show

Cache read: followings/632770-20120929132253/show
Cache fetch_hit: followings/632770-20120929132253/show

Cache read: followings/632770-20120929132253/show
Cache fetch_hit: followings/632770-20120929132253/show

问题:
这甚至是获取/缓存关联的“正确”实现吗? 性能怎么样?
在某些视图中(如示例中所示),它将在每个循环中达到缓存3次。在我的情况下,我在页脚中循环10个项目,因此每次请求都会有30个点击。这样很好,或者每个循环的单个n + 1查询会更好吗?

赞赏的建议和一般最佳实践:)

2 个答案:

答案 0 :(得分:2)

创建一种独特的方法来命中缓存而不是让它变得新鲜并不常见。

大多数情况下,您只需调用一个始终询问cache的方法,因为如果您在缓存键中包含一个对象,则updated_at字段用于构建关键。

对于您现在的示例,奇怪的部分是除了访问其关联之外,您实际上并未对Following模型执行任何操作。因此,您应该直接在Show模型上查询:

@recently_favorited_shows = Show.joins(:followings).order("followings.created_at DESC").uniq

然后在你的视图中,循环播放节目。只有一个查询,没有n + 1

如果您预计会有数千次点击,我建议您缓存@recently_favorited_shows的结果并每隔X分钟过期一次:

@recently_favorited_shows = cache_store.fetch('recently_favorited_shows', expires_in: 5.minutes){Show.joins(:followings).order("followings.created_at DESC").uniq}

另外请注意,如果您想在一段时间内完成,请在视图端对缓存使用情况进行详细说明:http://37signals.com/svn/posts/3113-how-key-based-cache-expiration-works

没有加入解决方案

编辑:现在,如果你在followings表中有很多行,那么这就是我要做的事情:

  • last_followed_at表格上创建一个字段shows,其上有索引
  • Following.rbbelongs_to :show, touch: :last_followed_at。这样,只要您在Following中添加新条目,它就会更新shows
  • 上的字段
  • 然后,要获得最新的关注节目,请执行以下操作:

    @shows = Show.order("last_followed_at DESC").limit(10) # Fast query of course
    

答案 1 :(得分:0)

这不能回答我的问题,但它解决了我的问题。以下是我将如何做到这一点:

@shows = Rails.cache.fetch("recently_favorited_shows", expires_in: 1.minutes) do
  Show.find(Following.order("created_at DESC").limit(10).collect(&:show_id))
end

查询非常快(每个约为0.8毫秒表示IRB控制台)