2012-05-31 41 views
1

我已經開始注意到,我的Rails應用程序生成太多的SQL語句,其中很多都不是必需的。我記得在某個地方讀這可能是一個問題,而且現在隨着我的數據增長,它明顯地減緩了應用程序的速度。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 

這裏涉及到的車型:

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 
+0

可能希望包含關係的基礎知識(模型定義)。 –

+0

確保您不會循環查詢。所有這些查詢都應該被轉換成一個IN語句 – Limey

+0

@DaveNewton - 我會盡量在一秒內添加,所有這些都是非常重要的,所以爲了清晰起見,我必須刪除一些內容。 – Raoot

回答

5

從Rails正在生成的查詢,它看起來像你正在做這樣的事情,它單獨加載每個藝術家,當你提到它:

release.tracks.each{ |t| t.artist } 

你應該急切地加載的藝術家,這樣在單個查詢它們預裝了:

release.tracks.includes(:artist).each{ |t| t.artist } 

includes方法是非常靈活的,並允許您急切地加載多個協會,甚至嵌套協會:

Release.first.includes(:releases_tracks => {:track => :artist}) 

這將加載第一個版本,那麼其所有ReleaseTracks,然後他們所有的曲目,以及所有曲目的藝術家只需4次查詢(每桌1張)。這比單獨加載每條記錄效率更高。

有關Eager Loading Associations in the Active Record Query interface guide部分的詳細信息。

+0

啊! 'release.tracks.each {| t | t.artist}'看起來很熟悉,所以我會看看我是否可以按照你的建議重構。謝謝! – Raoot

+0

實際上並不完全一樣,在我看來,tracklisting是通過'<%@ release.releases_tracks.sort_by {| releases_tracks | releases_tracks.position} .each do | releases_track | %>',然後藝術家用<%= releases_track.track.artists.map {| a | a.name} .join(「,」)%>'。我應該在其他地方做點什麼嗎? – Raoot

+0

我懷疑當你最初加載'@ release'時想使用'includes',就像:'@release = Release.foo.includes(:releases_tracks => {:track =>:artists})'但是如果你更新您的問題與更多關於您的模型的信息(以及您在評論中發佈的代碼)我或其他人將能夠提供更好的答案。 – georgebrock