我有一个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还有其他建议的缓存解决方案,用于经常更改的数据。
答案 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>
您可以使用includes
,PerformanceStat.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条记录根本不是最佳选择,加载所有记录将需要一段时间。为此,您必须使用以下宝石添加分页