Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 片段缓存和快速加载:如何充分利用这两个方面?_Ruby On Rails_Performance_Caching_Eager Loading_Fragment Caching - Fatal编程技术网

Ruby on rails 片段缓存和快速加载:如何充分利用这两个方面?

Ruby on rails 片段缓存和快速加载:如何充分利用这两个方面?,ruby-on-rails,performance,caching,eager-loading,fragment-caching,Ruby On Rails,Performance,Caching,Eager Loading,Fragment Caching,在我看来,片段缓存和即时加载(至少有时)是有点不一致的。假设我有一个用户,他有很多帖子,每个帖子都有很多评论,反过来也可以有很多评论,等等 当我必须呈现页面时,我可以选择急切地加载用户、她的所有帖子、他们的所有评论等等,以避免n-1次命中数据库。或者,我可以延迟加载每个对象,并依靠片段缓存仅查询数据库中新的或已更改的对象。同时使用片段缓存和即时加载似乎是浪费,因为我可能会执行一个非常复杂的查询并实例化许多对象,而只使用其中的一小部分 但是,如果我有一个应用程序,其中一个用户有许多Foo,这些Fo

在我看来,片段缓存和即时加载(至少有时)是有点不一致的。假设我有一个用户,他有很多帖子,每个帖子都有很多评论,反过来也可以有很多评论,等等

当我必须呈现页面时,我可以选择急切地加载用户、她的所有帖子、他们的所有评论等等,以避免n-1次命中数据库。或者,我可以延迟加载每个对象,并依靠片段缓存仅查询数据库中新的或已更改的对象。同时使用片段缓存和即时加载似乎是浪费,因为我可能会执行一个非常复杂的查询并实例化许多对象,而只使用其中的一小部分

但是,如果我有一个应用程序,其中一个用户有许多Foo,这些Foo又有许多条等等,但是在这个应用程序中,每个Foo都被创建,同时包含所有的条及其关联的对象,并且从那时起永不更改。在这种情况下,我希望对已经呈现的Foo使用片段缓存,但是当我必须加载一个新的Foo及其所有相关对象时,使用即时加载。毕竟,在更细粒度的级别缓存片段并没有什么好处


Rails中实现这一点的最佳方法是什么?我想我可以做一次查询,只获取Foo的id,然后在需要呈现每个Foo时,使用渴望加载进行显式查找。有更好/更优雅/更惯用的方法吗?

您可以在控制器中使用
fragment\u exists?
方法,以防止在所有对象已经在缓存中时立即加载它们。只有在第一次调用页面时才会出现这种情况

像这样:

  if fragment_exists? "my_cache_key_#{id}" 
    # load your object without eager loading here        
  else
    # eager load your objects here        
  end
然后在视图中使用片段切换:

<% cache("my_cache_key_#{@object.id}") do %>
...
...
...
<% end %>

...
...
...

那应该对你有用

基于@daviddb answer for Rails 4,我发现有必要在视图中
跳过_digest
,因为在控制器内为模板重新创建MD5哈希以进行比较似乎有点过分

另外,如果不在第一次找到对象,就很难获得具有上次修改的时间戳的对象,因此我发现在没有
的情况下进行初始查询很有帮助。includes(:object1,:object2)

views/customers/show.html.slim
(根据您首选的模板引擎进行调整)

controller/customers\u controller.rb

  def show
    customer = Customer.find(params[:id])
    if fragment_exist?(['customers/show', customer])
      @customer = customer
    else
      @customer = Customer.includes(account: :transactions).find(params[:id])
    end
  end

注意:通过设置
skip\u digest:true
,在更改此视图及其依赖的任何部分时,您需要在部署时清除缓存,以确保正确呈现新布局。

我使用lambda的缓存做了类似的事情。 下面你可以得到一个想法。它解决的问题是——获得最受欢迎的用户是一项繁重的操作,需要>5秒。但使用lambda,您可以缓存用户列表

controller:
def index
 @users = -> { User.by_rating }
end

view:
= cache "rating-list", expires_in: 1.day do
  - @users.call.each do |user|
     = render user

你们可以使用俄罗斯玩偶缓存来解决这类问题,比如说,我们在你们可以使用的主页上有评论和作者的帖子

//家庭控制器
def索引
@帖子=帖子。包括(:作者,:评论)。限制(10)
结束
看法


我在试图访问碎片时得到了这个消息,是否存在?在控制器中,
***NoMethodError Exception:对于
Ah,未定义的方法'fragment\u exists',看起来您希望
fragment\u exist?
没有复数化,这种方法要么对我不起作用,要么停止工作。在控制器Rails中检查
视图/响应/任务-ab203634-3ce6-44f0-88a9-7e62b25d9637/1-20201009164529/js_init
但在视图中检查
视图/欢迎/仪表板:d450ca1537e85d680d530f7909373869/响应/任务-ab203634-3ce6-44f0-88a9-7E62BD9637/1-20201009164529//_init
。注意不同的前缀
controller:
def index
 @users = -> { User.by_rating }
end

view:
= cache "rating-list", expires_in: 1.day do
  - @users.call.each do |user|
     = render user
- cache ["v1#home", @posts.maximum(:updated_at).to_i] do
  - @post.each do |post|
    - cache ["v1#post_in_home", @post.id, @post.updated_at.to_i] do
      = post.title
      = post.author.name
      = post.content

      - cache ["v1#comments_in_post", @post.comments.maximum(:updated_at).to_i] do
        - @comments.each do |comment|
          = comment.author
          = comment.content