Rails 3中的Eager loading是什么?

3

我正在尝试学习如何提高Rails应用程序的性能,第一步是研究贪婪加载。

我已经配置了bullet gem,它显示了我可以使用贪婪加载的地方,但是,我不太确定如何使用这个工具!

下面是一个示例日志:

2012-04-26 15:59:34
0.0.0.0:3000http://0.0.0.0:3000/animals
N+1 Query detected
  Animal => [:client]
  Add to your finder: :include => [:client]
N+1 Query method call stack
  N+1 Query method call stack
  /Users/dannymcclelland/Projects/premvet/app/views/animals/index.html.erb:26:in `block in _app_views_animals_index_html_erb__2796162405947806753_70316525286320'
  /Users/dannymcclelland/Projects/premvet/app/views/animals/index.html.erb:22:in `_app_views_animals_index_html_erb__2796162405947806753_70316525286320'
  /Users/dannymcclelland/Projects/premvet/app/controllers/animals_controller.rb:7:in `index'2012-04-26 15:59:34[WARN] user: dannymcclelland
0.0.0.0:3000http://0.0.0.0:3000/animals
Unused Eager Loading detected
  Animal => [:id, :AnimalName, :Species]
  Remove from your finder: :include => [:id, :AnimalName, :Species]2012-04-26 16:00:56

突出的行是:

N+1 Query detected
Animal => [:client]
Add to your finder: :include => [:client]

并且

Unused Eager Loading detected
Animal => [:id, :AnimalName, :Species]
Remove from your finder: :include => [:id, :AnimalName, :Species]

我不确定“finder”的定义是什么。它是视图中的块还是控制器中的块?
接下来我看到的第一部分日志,控制器如下:
def index
@animals = Animal.page(params[:page]).per_page(15)

respond_to do |format|
  format.html # index.html.erb
  format.json { render json: @animals }
end
end

模型:

class Animal < ActiveRecord::Base
  self.table_name = 'animal'
  self.primary_key = 'PVID'

  attr_accessible :AddedBy, :Age, :AnimalBFAmount, :AnimalBalance, :AnimalName, :Archive,    :BillType, :Breed, :ChronicStatus, :Class, :Classification, :ClientKey, :Colour, :Date1, :DateOfBirth, :DateofBirth, :Dead, :DiaryQueue, :DiscField, :DrugsAtCost, :DrugsNoVAT, :ESDAmount, :ESDType, :FNote, :FirstRegisteredDate, :Height, :IDNumber, :Insured, :InsuredWith, :IsClient, :IsClientDate, :IsMaster, :LastBilledAmount, :LastBilledDate, :LastConsDate, :LastContributionDate, :LastPaidDate, :LastWeightDate, :Locked, :LoyaltyMultiplier, :LoyaltyPoints, :MR_Flag_0, :MR_Flag_1, :MR_Flag_10, :MR_Flag_11, :MR_Flag_12, :MR_Flag_13, :MR_Flag_14, :MR_Flag_15, :MR_Flag_2, :MR_Flag_3, :MR_Flag_4, :MR_Flag_5, :MR_Flag_6, :MR_Flag_7, :MR_Flag_7, :MR_Flag_8, :MR_Flag_9, :Mileage, :Neutered, :NextApptDate, :ORT, :OldSex, :Opt_Flag_0, :Opt_Flag_1, :Opt_Flag_2, :Opt_Flag_3, :Opt_Flag_4, :Opt_Flag_5, :Opt_Flag_6, :Opt_Flag_7, :PVID, :PreferredContact, :PreferredUser, :Ref1, :RefPrac, :ReferredBy, :SSDType, :SeenInPeriod, :SendBill, :Sex, :SiteAnimal, :Species, :Status, :SurcAmount, :SurcType, :SurgeryNumber, :TBU, :TOSAmount, :TOSDrugs, :TOSFees, :TOSType, :Weight

  belongs_to :client, :foreign_key => 'ClientKey'
  has_many :clinicals, :foreign_key => 'PVID'
  has_many :labs, :foreign_key => 'PVID'
  has_many :consults, :foreign_key => 'pvid'
  has_many :sheets, :foreign_key => 'PVID'

  default_scope :order => "Dead ASC, AnimalName ASC"
end

请注意,我正在使用一个传统的数据库,因此列名等可能会很奇怪。
该视图包含以下内容:
<% @animals.includes(:client).each do |animal| %>
  <tr>
    <td><%= animal.id %></td>    
    <td><%= animal.AnimalName %></td>
    <td><%= link_to animal.client.Surname, animal.client %></td>    
    <td><%= animal.Species %></td>
    <td><%= animal.Breed %></td>
    <td><%= animal.Dead %></td>    
    <td><%= link_to 'Show', animal %></td>
  </tr>
<% end %>

那么,我应该将其他推荐列添加到“查找器”视图中吗?还是其他地方?
非常感谢你的帮助!
1个回答

3

在您的控制器中,您希望更新查询以包括客户端:

@animals = Animal.includes(:client).page(params[:page]).per_page(15)

除此之外还有什么变化吗?还是就这么简单? - dannymcc
简单来说,Rails 只会运行两个查询——一个针对 Animal 表,另一个针对 Client 表。你不需要在视图等方面进行任何更改。 - Dylan Markow
那么 :client 是相关表的名称?我以为我必须列出我要查找的每个列!糟糕。 - dannymcc
由于 Animal 模型中有一个 belongs_to :client 语句,Rails 知道这两个模型是相关联的。这就是为什么在你的视图中,animal.client.Surname 能够正常工作。因此,通过执行 includes(:client),这告诉 Rails “一次性加载所有相关联的客户端,而不是在需要时逐个加载它们”。 - Dylan Markow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接