2011-08-12 65 views
1

新的rails/ruby​​(使用rails 3和ruby 1.9.2),并试图摆脱一些不必要的查询被执行。Rails/Active Record .save!效率问题

当我运行的每一个做:

apples.to_a.each do |apple| 
    new_apple = apple.clone 
    new_apple.save! 
end 

和我检查的SQL日志,我看到三个select语句后跟一个INSERT语句。选择语句看起来完全没有必要。例如,它们是这样的:

SELECT Fruit。* from Fruits where Fruit.ID = 5 LIMIT 1;
从颜色中选择颜色*,其中Color.ID = 6 LIMIT 1;
SELECT TreeType。* from TreeTypes where TreeType.ID = 7 LIMIT 1;
插入苹果(Fruit_id,color_id,treetype_id)值(6,7,8)返回“id”;看起来,这不会花费很多时间,但是当我有70k插入点运行时,我打赌每个插入点的这三个选择将花费相当多的时间。

所以我想知道以下几点:

  • 这是典型的ActiveRecord的/ Rails的.save!方法,还是以前的开发人员添加某种自定义代码?
  • 这三个选择语句,是否为每个项目执行,会导致明显的额外时间?
  • 如果它被内置到rails/active记录中,它是否会被轻松绕过,如果这样可以使它更有效地运行?

回答

3

您必须验证您的关联上保存这么发生的事情,这样的事情:

class Apple < ActiveRecord::Base 
    validates :fruit, 
    :presence => true 
end 

为了验证这种关系,记录必须加载,而这需要每个验证单独进行一次,每个记录依次进行。这就是save!

标准的行为,你可以保存而不验证,如果你觉得自己的生活危险:

apples.to_a.each do |apple| 
    new_apple = apple.clone 
    new_apple.save(:validate => false) 
end 

的更好的方法是通过做大量的插入,如果您的RDBMS支持它直接操作SQL记录。例如,MySQL将允许您通过一个INSERT调用插入数千行。 (或验证的建议以上)方法的:你通常可以通过利用Apple.connection接入层,使您可以任意SQL做这个事情像execute

0

我猜是有before_save编辑电话所谓的是查找水果的颜色和类型,并在保存水果时将其与其余属性一起存储 - 在这种情况下,这些查找是必要的...

通常我不希望activerecord做不必要的查找 - 尽管这并不意味着它总是有效... ...

+0

公平起见,ActiveRecord只会做你所做的事,即使有时你做没有意识到你要告诉它做什么。 – tadman