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查询会更好吗?
赞赏的建议和一般最佳实践:)
答案 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.rb
:belongs_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控制台)