使用嵌套:include时,Ruby on Rails性能很差

时间:2010-03-17 23:29:57

标签: ruby-on-rails ruby performance

我有三个看起来像这样的模型:

class Bucket < ActiveRecord::Base
  has_many :entries
end

class Entry < ActiveRecord::Base
  belongs_to :submission
  belongs_to :bucket
end

class Submission < ActiveRecord::Base
  has_many :entries
  belongs_to :user
end

class User < ActiveRecord::Base
   has_many :submissions
end

当我检索一系列条目时,执行以下操作:

@entries = Entry.find(:all,
                      :conditions => ['entries.bucket_id = ?', @bucket],
                      :include    => :submission)

虽然我获得了大量额外查询,但是性能非常快,因为视图使用了Submission.user对象。但是,如果我将用户添加到:include语句,则性能变得非常糟糕,并且需要超过一分钟才能返回总共50个条目和5个用户之间的提交。当我运行相关的SQL命令时,它们会在一秒钟内完成 - 每个查询的SQL查询性能都相同。

@entries = Entry.find(:all,
                      :conditions => ['entries.bucket_id = ?', @bucket],
                      :include    => {:submission => :user})

为什么第二个命令与第一个命令相比会有如此可怕的性能?

3 个答案:

答案 0 :(得分:0)

这是因为你在第二个语句中有一个双连接。所以结果的数量更大。

结果越大,结果就越慢。

答案 1 :(得分:0)

我不确定性能是否会好得多,但请尝试:

@bucket.entries.find(:all, :include => {:submission => :user})

我真的只熟悉MySQL,但如果您的数据库支持它们,索引将显着提高性能。我通常在我的迁移中执行此操作,例如:

def self.up
  create_table :entries do |t|
    t.references :submission 
    t.references :bucket
    # other fields...
  end

  add_index :entries, :submission_id
  add_index :entries, :bucket_id
end

答案 2 :(得分:0)

这最终成为整个对象图中用户模型的序列化/反序列化的问题。通过在Entry和Submission模型上缓存相关数据,我们可以避免查找User并节省了大量时间。