【问题标题】:Index view loading very slowly索引视图加载非常缓慢
【发布时间】:2019-02-11 05:44:10
【问题描述】:

我有一个模型 Schools 和一个模型 PerformanceStats。

PerformanceStat 
belongs_to :school

School
has_one :performance_stat

PerformanceStat 的索引页面显示所有 2,000 个性能统计信息,以及 school.name、school.score 和 school.city,我需要访问 school.id 和 school.slug。

控制器:

def index
   @performance_stats=PerformanceStat.all
end

我的查看代码:

 <tbody>
 <% @performance_stats.each do |stat| %>
   <% school = School.find(stat.school_id)%>
    <tr>
      <td><%= link_to school.name, school_path(city: school.city.parameterize.truncate(80, omission: ''), slug: school.slug) %></td>
     <td><%= number_with_precision(school.score, precision: 2)%></td>

然后视图继续显示性能统计信息。

此视图加载非常缓慢....10-20 秒。我怎样才能加快速度?我已经尝试过 PerformanceStats.scoped,并提取学校统计数据并从数组中进行选择,但这些似乎没有帮助。有没有办法让我在不为每个 PerformanceStat 找到学校的情况下访问学校属性?我相信 School.find 位正在大大减慢速度。

我在 PerformanceStat 中的 :school_id 和 School 模型中的 :score 和 :slug 上有索引。

更新:

所选答案中添加缓存的建议导致 SchoolsController 的索引操作中的这行代码:

fresh_when etag: @performance_stats

加载时间降至 18 毫秒。这个解决方案对我很有用,因为索引操作的内容不会经常改变。该数据每年更新一次。 This link 为频繁更改的数据提供了其他建议的缓存解决方案。

【问题讨论】:

    标签: ruby-on-rails performance caching ruby-on-rails-5


    【解决方案1】:

    PerformanceStat.all 是一个繁重的查询,如果您在此表中有大量数据并且它将为每个performance stat 寻找学校。 从您的代码中我可以理解的是,您在这里面临 (N + 1) 个问题。

    注意:您不应该从您的视图或助手中触发查询并让控制器执行所有操作。

    例如在您的代码中:

    <% @performance_stats.each do |stat| %>
       <% school = School.find(stat.school_id)%> <- #THIS IS WRONG & LET THE ASSOCIATIONS DO ALL THE ACTION ON ITS OWN
         <tr>
           <td><%= link_to school.name, school_path(city: school.city.parameterize.truncate(80, omission: ''), slug: school.slug) %></td>
           <td><%= number_with_precision(school.score, precision: 2)%></td>
    

    您可以使用includesPerformanceStat.includes(:school),它将获取每个 PerformanceStat 的所有学校。

    您的控制器代码应该是:

    @performance_stats = PerformanceStat.includes(:school)

    而不是:@performance_stats = PerformanceStat.all

    您的视图代码现在将是:

    <% @performance_stats.each do |stat| %>
       <% school = stat.school %> #make sure all stats have a school assigned to them otherwise you can put a check below whether the school is nil or not
         <tr>
           <td><%= link_to school.name, school_path(city: school.city.parameterize.truncate(80, omission: ''), slug: school.slug) %></td>
           <td><%= number_with_precision(school.score, precision: 2)%></td>
    

    【讨论】:

    • 感谢,此更改将加载时间减少到 4-5 秒。还是有点长,但好多了!
    • 您可以通过仅选择您需要的列以及分页来减少时间。也可以进行缓存,这将是优化它的最佳解决方案。
    • 哇,我的索引控制器操作中的这一简单行已将加载时间减少到 18 毫秒! 'fresh_when etag:@performance_stats'
    • 这是我今天从您的评论中学到的新东西!谢谢和祝贺!
    【解决方案2】:

    这里有很多东西。首先将您的控制器方法更改为这个,否则您将遇到 n+1 个查询

    def index
     @performance_stats=PerformanceStat.includes(:school)
    end
    

    既然你已经迫不及待地加载了学校,现在你可以直接在你的视图中访问它

    <% stat.school %>
    

    一次加载近 2000 条记录根本不是最佳选择,加载所有记录需要一段时间。为此,您必须使用以下宝石添加分页

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多