Rails Rails 5 - 将会有更快的 render collection 以及优化小细节

huacnlee · 2015年05月25日 · 最后由 huacnlee 回复于 2015年06月18日 · 7965 次阅读
本帖已被设为精华帖!

https://dev.firmafon.dk/blog/rails-5-much-faster-collection-rendering/

Rails 5 将会带来更快的 collection render fragment (有 cache 的). Pull Request 已经合并了: https://github.com/rails/rails/pull/18948

原理是内部用了 Cache multi read,能有效减少 Cache 服务的连接,从而加快速度。

用法

<%= render partial: 'item', collection: @items, cache: true %>

或者

<%= render partial: 'item', collection: @items, cache: Proc.new{|item| [item, 'show']} %>

在 Rails 5 发布前,大家可以用 multi_fetch_fragments。 已经在 Ruby China 上面用上,并刚刚上线了哦。

https://github.com/ruby-china/ruby-china/commit/dde8d199292571f9dd262c62b1495d58f2374214


题外话

循环 render partial vs render :collection

Rails 允许 render 的时候使用 :collection 参数,这样也能有效减少耗时哦!

Before

<% @replies.each do |reply| %>
  <%= render partial: 'reply', reply: reply %>
<% end %>

After:

<%= render partial: 'reply', collection: @replies %>

去掉 includes,当有 render partial cache 的时候

在这类有 partial cache 的情况下,故意 N+1 能有效减少查询开销哦。 比如 Ruby China 回帖这种情况,以前我们为了避免 N+1,所以会用 includes 方法

Controller:

def show
  @replies = @topic.replies.includes(:user)
end

View:

<%= render partial: 'reply', collection: @replies, cache: true %>

但由于页面绝大大多数下,由于 Cache 存在,已经不再需要 user 对象了,所以去掉 includes(:user) 能少掉查询用户的动作。

参考这个 Commit 7793d342bab3069221cd9cba610d0b8c864332e3

实际效果,两个动作一起处理,Ruby China 话题列表从 上一次优化 的 60ms 左右缩短到了 42ms 左右了。

共收到 35 条回复

很棒 前几天正好在优化自己的小demo,发现render partial这边确实问题比较大,没想到现在马上就改了

:plus1:

呀,好期待耶……什么什么时候会正式出Rails 5啊?

嗯,期待rails5

:plus1:

:plus1: 以前都是靠 Rails.cache + memcached 来做这种 n+1,现在方便了很多

非常棒

非常棒。👍

Nice :plus1:

这个太棒了.

昨天在greenruby上看到了这篇,没来得及细看,今天再看下,确实很棒

Jeff Atwood 說 https://twitter.com/codinghorror/status/602375823996235776 "we see 15ms page render times on Stack Overflow. At Discourse we are lucky to get 5x that at best"

15ms, 不知道 Ruby 什麼時候可以追上。

17楼 已删除

不错哗

其原理是不是把n+1的cache查询减少到1次查询?

def show1
  @replies = @topic.replies.includes(:user)
end

def show2
  @replies = @topic.replies
end

show1中是为了解决N+1的情况。show2中是因为页面已经做了cache,所以不需要再user对象了,如果这个show2的东西更新频率很高,那么是不是意味着我的cache一直要被更换掉呢?一般这种情况有什么缓存策略来解决问题呢?

#20楼 @clarkyi

【故意 N+1 能有效减少查询开销】, 我觉得要看场景

如果系统 user 本身就很少 那几次 n+1 后就都 cache 了, 如果 user 数量很多活跃度很随机,仍然不容易命中这种 "故意 N+1" 的 cache

怎么修改不了头像

这个对jbuilder里面的partial没效果吗 @xyuanu

不错ya

期待 Rails 5 能在性能改善更多!!!

:plus1:

Dalli可能对这个multi fetch 有影响。

https://github.com/mperham/dalli/issues/106

rails 5 什么时候发布啊

如果这个 @items 里有不同的类型,不知道是否依然有效?

@huacnlee 但是include是不是可以减少第一次访问的时间呢?因为这时候没有cache

我跟 @bluecoda 有一樣的疑問 不使用includes雖然在有cache的時候可以少一次 但是在第一次或是cache expired的時候 不是會出現n+1 queries的問題? 能在深入說明下嗎?

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册