Rails批量构建和保存

3

我有类似以下的内容:

module Bar < ActiveRecord::Base
  belongs_to :foo
  ...

module Foo < ActiveRecord::Base
  has_many :bars, dependent: :destroy

  def build_bars
    1000.times do |i|
      bars.build(num: i)
    end
  end

  def create_default_bars!
    build_bars
    save
  end

请注意,Foo#build_bars很便宜。即使它循环1000次,也需要很少的时间。但是,一旦你点击save,ActiveRecord突然决定执行1000个插入操作,这非常慢。
我该如何编写一个自定义的save_the_bars方法,以便为我构建的所有bars执行单个批量INSERT查询(提醒您,1000个build显然非常便宜),但在此示例中作为save的替代品?
我期望你能给出与此博客文章推荐 #3 类似的答案:

https://www.coffeepowered.net/2009/01/23/mass-inserting-data-in-rails-without-killing-your-performance/

但由于我的示例使用了 build 并依赖于一些稍微复杂的 Rails 魔法,因此如何将其转换并不立即显然。加分项为基准测试!

1个回答

3

我会尝试使用 activerecord-import gem。

def save_the_bars(bars)
  Bars.import bars
end

这个导入调用会根据底层数据库适配器的最高效方式执行操作。非常棒,不是吗?

额外加分项:基准测试


我是提问者,按照上面的建议,我做了以下操作:

def build_bars
  built_bars = []
  1000.times do |i|
    built_bars << bars.build(num: i)
  end
  built_bars
end

def create_default_bars
  save
  Bar.insert built_bars, validate: false
  reload
end

这为我们带来了不错的加速效果,只需要付出相对较小的努力。我仍然怀疑可以通过利用insert的微妙之处获得更多的加速效果,但目前我对此感到满意。在我的使用情况下,关闭验证是安全的,因为生成所有Bar的方法保证会生成有效的Bar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接