Rails执行太多SQL

Rao*_*oot 1 sql ruby-on-rails ruby-on-rails-3

我开始注意到终端我的Rails应用程序产生了太多的SQL语句,其中许多都不是必需的.我确实记得在某个地方阅读这可能是一个问题而且现在随着我的数据增长它显着减慢了应用程序的速度.

例如,我有包含曲目的版本.艺术家可以分配到曲目和发行.当我加载一个只有8个轨道的版本时,它似乎正在运行DB中的每个轨道来找到这些关系!?!

例如,请参见下文,这是一个非常小的示例,但这些轨道实际上都与该版本无关.它正在经历数据库中的每个轨道!

任何一般指针?

Artist Load (0.6ms)  SELECT `artists`.* FROM `artists` INNER JOIN `artists_tracks` ON `artists`.`id` = `artists_tracks`.`artist_id` WHERE `artists_tracks`.`track_id` = 12
  Artist Load (0.6ms)  SELECT `artists`.* FROM `artists` INNER JOIN `artists_tracks` ON `artists`.`id` = `artists_tracks`.`artist_id` WHERE `artists_tracks`.`track_id` = 19
  Artist Load (0.6ms)  SELECT `artists`.* FROM `artists` INNER JOIN `artists_tracks` ON `artists`.`id` = `artists_tracks`.`artist_id` WHERE `artists_tracks`.`track_id` = 21
  Artist Load (0.9ms)  SELECT `artists`.* FROM `artists` INNER JOIN `artists_tracks` ON `artists`.`id` = `artists_tracks`.`artist_id` WHERE `artists_tracks`.`track_id` = 22
  Artist Load (0.7ms)  SELECT `artists`.* FROM `artists` INNER JOIN `artists_tracks` ON `artists`.`id` = `artists_tracks`.`artist_id` WHERE `artists_tracks`.`track_id` = 23
  Artist Load (0.6ms)  SELECT `artists`.* FROM `artists` INNER JOIN `artists_tracks` ON `artists`.`id` = `artists_tracks`.`artist_id` WHERE `artists_tracks`.`track_id` = 24
  Artist Load (0.9ms)  SELECT `artists`.* FROM `artists` INNER JOIN `artists_tracks` ON `artists`.`id` = `artists_tracks`.`artist_id` WHERE `artists_tracks`.`track_id` = 25
  Artist Load (1.0ms)  SELECT `artists`.* FROM `artists` INNER JOIN `artists_tracks` ON `artists`.`id` = `artists_tracks`.`artist_id` WHERE `artists_tracks`.`track_id` = 26
  Artist Load (0.6ms)  SELECT `artists`.* FROM `artists` INNER JOIN `artists_tracks` ON `artists`.`id` = `artists_tracks`.`artist_id` WHERE `artists_tracks`.`track_id` = 27
  Artist Load (0.9ms)  SELECT `artists`.* FROM `artists` INNER JOIN `artists_tracks` ON `artists`.`id` = `artists_tracks`.`artist_id` WHERE `artists_tracks`.`track_id` = 28
  Artist Load (0.6ms)  SELECT `artists`.* FROM `artists` INNER JOIN `artists_tracks` ON `artists`.`id` = `artists_tracks`.`artist_id` WHERE `artists_tracks`.`track_id` = 29
  Artist Load (0.6ms)  SELECT `artists`.* FROM `artists` INNER JOIN `artists_tracks` ON `artists`.`id` = `artists_tracks`.`artist_id` WHERE `artists_tracks`.`track_id` = 30
  Artist Load (0.6ms)  SELECT `artists`.* FROM `artists` INNER JOIN `artists_tracks` ON `artists`.`id` = `artists_tracks`.`artist_id` WHERE `artists_tracks`.`track_id` = 31
Run Code Online (Sandbox Code Playgroud)

这是涉及的模型:

class Artist < ActiveRecord::Base  
  has_many :artist_releases
  has_many :releases, :through => :artist_releases 
  has_many :artists_tracks
  has_many :tracks, :through => :artists_tracks
end

class ArtistRelease < ActiveRecord::Base
  belongs_to :artist
  belongs_to :release
end

class ArtistsTrack < ActiveRecord::Base
  belongs_to :artist
  belongs_to :release
  belongs_to :track
end

class Release < ActiveRecord::Base
  has_many :artist_releases
  has_many :artists, :through => :artist_releases
  accepts_nested_attributes_for :artists, :reject_if => lambda { |a| a[:name].blank? }
  accepts_nested_attributes_for :artist_releases    
  has_many :releases_tracks, :dependent => :destroy
  has_many :tracks, :through => :releases_tracks, :order => "releases_tracks.position"
  accepts_nested_attributes_for :tracks, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => :true
  accepts_nested_attributes_for :releases_tracks    
end

class ReleasesTrack < ActiveRecord::Base
  default_scope :order => 'releases_tracks.position ASC'
  acts_as_list :scope => :release_id
  belongs_to :release
  belongs_to :track
end

class Track < ActiveRecord::Base
  has_many :releases_tracks, :dependent => :destroy
  has_many :releases, :through => :releases_tracks
  has_many :artists_tracks
  has_many :artists, :through => :artists_tracks
  accepts_nested_attributes_for :artists, :reject_if => lambda { |a| a[:name].blank? }
  accepts_nested_attributes_for :artists_tracks
end
Run Code Online (Sandbox Code Playgroud)

geo*_*ock 5

从Rails生成的查询中,看起来你正在做这样的事情,当你引用它时,它会单独加载每个艺术家:

release.tracks.each{ |t| t.artist }
Run Code Online (Sandbox Code Playgroud)

您应该热切地加载艺术家,以便在单个查询中预先加载它们:

release.tracks.includes(:artist).each{ |t| t.artist }
Run Code Online (Sandbox Code Playgroud)

includes方法非常灵活,允许您急切地加载多个关联,甚至嵌套关联:

Release.first.includes(:releases_tracks => {:track => :artist})
Run Code Online (Sandbox Code Playgroud)

这将加载第一个Release,然后是所有的ReleaseTracks,然后是所有的Tracks,以及仅4个查询中的所有Tracks'Artists(每个表1个).这比单独加载每条记录更有效.

"Active Record查询"界面指南中的"预先加载关联 "一节中提供了更多信息.