預先載入子記錄討論的問題和“消極式載入”是相同的。通常Active Record會延遲從資料庫中載入子記錄,直到你需要他們,例如,通過Rdoc中的例子,我們假定部落格程式有一個Model,像下面這樣:
class Post < ActiveRecord::Basebelongs_to :authorhas_many :comments, :order => 'created_on DESC'end
如果我們遍曆所有的post,訪問作者和評論屬性,我們使用一個Sql查詢來返回posts表中的多條記錄,並且對於每條post記錄都要執行一次Sql來訪問authors表和comments表,總共是2n+1次。
for post in Post.find(:all)puts "Post: #{post.title}"puts "Written by: #{post.author.name}"puts "Last comment on: #{post.comments.first.created_on}"end
上面的代碼存在著嚴重的效能問題,我們可以通過find方法的:include參數來修正它,在find方法被執行時,會列出需要消極式載入的關聯。Active Record會很聰明地使用一條SQL一次載入資料,如果有100個post,和上面的代碼相比,下面的代碼將會消除100次資料庫查詢:
for post in Post.find(:all, :include => :author)puts "Post: #{post.title}"puts "Written by: #{post.author.name}"puts "Last comment on: #{post.comments.first.created_on}"end
這個例子還可以更簡化,只使用一條SQL:
for post in Post.find(:all, :include => [:author, :comments])puts "Post: #{post.title}"puts "Written by: #{post.author.name}"puts "Last comment on: #{post.comments.first.created_on}"end
預先載入子記錄並不能保證改善效能(事實上,如果你的資料庫不支援左串連,那麼你就不能使用消極式載入,如果你使用的是oracle8,就必須要升級到oracle9才可以),因為預先載入在Sql中加入了所有的表,這樣就會有很多記錄被載入後轉換成Model類的對象,這樣就有可能導致記憶體使用量的問題,特別是當一條記錄有很多條子記錄時,這種情況就更明顯,與一條條地消極式載入子記錄相比,預先載入會佔用更多的伺服器記憶體。
如果你使用了:include,你需要使用find方法的參數消除列名的歧義,在列名前添加表名來區分,在下面的例子中,title列需要添加表名首碼:
for post in Post.find(:all, :conditions => "posts.title like '%ruby%'",:include => [:author, :comment])# ...end