【问题标题】:Optimizing a Rails 3.0 query which returns hundreds of records优化返回数百条记录的 Rails 3.0 查询
【发布时间】:2011-06-26 18:37:16
【问题描述】:

环境:Rails 3.0.6 和 MySQL

我有以下两种型号:

class Employee < ActiveRecord::Base
  belongs_to :user
  belongs_to :manager
end

class Manager < ActiveRecord::Base
  has_many :employees
end

我有一个页面,其中显示给定用户的所有员工及其所有直接经理。此页面通常显示数十条记录,但对于执行级别的用户,可能会显示多达 1000 条记录。 (出于各种原因,我们不想使用分页。)

渲染页面的控制器方法如下(完整展示)

def manage_reports

  @tab = "home"
  @sub = "manage"

  add_breadcrumb I18n.t("home_menu.My Reports"), :manage_reports_path

  @my_reports = current_user.employees.includes(:manager).order('manager.name)      

  respond_to do |format| 
    format.html
    format.pdf { render :layout => false } if params[:format] == 'pdf'
      prawnto :filename => "employee_list.pdf", :prawn => { }
  end  
end

视图是一个简单的表格,显示员工的信息列和经理的两列信息(姓名和标签字段)。这两个模型都没有超过十列​​。两者都已编入索引。

在大约 600 份报告的情况下,页面的加载时间范围从

我有几个问题:

1) 占用 80% 时间的控制器中实际发生了什么?是将报告加载到内存中吗?我们不应该期望能够更快地将这么多记录加载到页面上吗?

2) manager 表有一个带有一段文本的“bio”字段。在包含经理关联时如何排除该列? Rails 3.0.x 文档在这个主题上似乎特别不完整。甚至有必要排除该列吗?如果未在视图中访问 bio 列,它是否曾经加载到内存中?我对在 Rails 3 中包含关联现在是急切加载还是延迟加载感到困惑。查看控制台中的查询,只有一个 SQL 查询加载了员工和经理的所有列。

更新:

这是 NewRelic 中的交易明细。 (为格式化道歉)

                          Time  Avg calls   Avg time (ms)  
* manage_employees          79  1           1,676  
* Manager#find              11  81          227  
* Tag#find                   9  82          185  
* Employee#find              1  2           19  
* Database SQL - SELECT     .3  1           5  
* User#find                 .1  1           3  

视图代码是一个简单的表格。每一行如下:

<td align="left">  <%= link_to emp.mgr.name, show_mgr_path(emp.mgr) %></td>      
<td align="center"><%= emp.mgr.lang       %></td>       
<td align="center"><%= emp.num        %></td>   
<td align="center"><%= emp.status         %></td>           
<td align="center"><%= emp.test_score     %></td>
<td align="center"><%= emp.test_date      %></td>   
<td align="center"><%= emp.serviceyrs     %></td>
<td align="left">  <%= emp.tag_list.to_s  %></td>

【问题讨论】:

  • 你能把视图代码粘贴进去吗?数据库和渲染占响应时间的百分比是多少?
  • 我已经更新了上面的帖子。我花了很长时间认为是导致问题的标签的检索,但完全删除标签并没有对响应时间产生任何重大变化。
  • 愚蠢的问题,但您是否将 'emp.mgr' 缩写为示例,或者这实际上是您的代码?
  • Dan,为了更贴合,我把它缩写了。

标签: mysql performance ruby-on-rails-3 activerecord associations


【解决方案1】:

阅读您的观点,我想我已经发现了潜在的问题:

<td align="left">  <%= emp.tag_list.to_s  %></td>

您的部分似乎正在执行另一个查询以获取标签列表。检查您的日志——如果是 cae,有 600 条记录,这是一个经典的 N+1 问题,可以解释您的 15 秒响应时间。

【讨论】:

  • 这就是我要求查看视图的原因。
  • 奇怪的是,我首先将标签添加到了 include 中,然后遍历了 employee.tag(即在一次调用中预加载了所有标签信息)并且没有任何区别。即使完全删除标签数据也不会改变性能。这会显示在“manage_reports”控制器下吗?
  • 只有这么多你可以说服 ActiveRecord 塞进一个查询中,尤其是在多对多关联的情况下。如果没有完全访问您的代码的权限,我没有什么其他建议可以解决您的时间问题。删除对 emp.tag_list 的调用,看看这对你的表现有什么影响。如果可行,请重新评估是否需要将标签放在那里,或者进行优化——也许将标签名称缓存为模型上的简单文本字段?
  • 有没有办法从经理模型中排除长文本字段?旧语法 { :exclude => :bio } 似乎不再有效。不过,该列可能是 manager 表中 90% 的数据。
  • 这可能是问题所在吗?您是否检查过您的开发日志以了解问题出在哪里?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多