索引视图加载非常缓慢

时间:2018-09-06 03:10:24

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

我有一个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的index操作中出现以下代码行:

fresh_when etag: @performance_stats

加载时间降至18ms。该解决方案对我来说非常有效,因为index动作的内容不会经常更改。该数据每年更新一次。 This link还有其他建议的缓存解决方案,用于经常更改的数据。

2 个答案:

答案 0 :(得分: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>

答案 1 :(得分:1)

这里有几件事。首先将您的控制器方法更改为该方法,否则您将遇到n + 1个查询

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

由于您已经热切地加载了学校,现在您可以直接在视图中访问它,

<% stat.school %>

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

相关问题