[英]Rails build and save in bulk
I've got something like the following: 我有类似以下内容:
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
Notice that Foo#build_bars
is cheap. 请注意, Foo#build_bars
很便宜。 Even though it loops 1000 times, it takes very little time. 即使它循环1000次,也只需要很少的时间。 But then, once you hit save
, suddenly ActiveRecord decides to perform 1000 inserts, which is incredibly slow. 但是,一旦你点击save
,突然ActiveRecord决定执行1000次插入,这非常慢。
How can I write a custom save_the_bars
method such that it performs a single bulk INSERT query for all of the bars
I have built up (I remind you, the 1000 build
s are apparently very cheap), but which functions as a drop-in replacement for save
in this example? 如何编写自定义save_the_bars
方法,以便它为我构建的所有bars
执行单个批量INSERT查询(我提醒您,1000 build
显然非常便宜),但它可以作为替代品在这个例子中save
?
I'm expecting an answer along the lines of recommendation #3 of this blog post: 我希望能够按照这篇博客文章的第3号推荐回答:
https://www.coffeepowered.net/2009/01/23/mass-inserting-data-in-rails-without-killing-your-performance/ https://www.coffeepowered.net/2009/01/23/mass-inserting-data-in-rails-without-killing-your-performance/
But since my example uses build
and relies on some slightly nontrivial rails magic, it isn't immediately obvious how to translate it over. 但是因为我的例子使用了build
并且依赖于一些稍微不重要的rails魔法,所以如何翻译它并不是很明显。 Bonus points for benchmarks! 基准的奖励积分!
I would try the activerecord-import
gem. 我会尝试activerecord-import
gem。
def save_the_bars(bars)
Bars.import bars
end
This call to import does whatever is most efficient for the underlying database adapter. 这种对导入的调用会对底层数据库适配器执行最有效的操作。 Pretty slick, eh? 漂亮,嗯?
For bonus points: Benchmarks 奖励积分: 基准
Question-asker here, hijacking this answer with details on what I did following the above suggestion: 提问者在这里,劫持了这个答案,详细说明了我按照上述建议做了什么:
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
This gave a nice speedup for relatively little effort. 这为相对较少的努力提供了很好的加速。 I still suspect that more speedup could be had (by leveraging the nuances of insert
) but I'm satisfied with this for now. 我仍然怀疑可以获得更多的加速(通过利用insert
的细微差别),但我现在对此感到满意。 In my use case, it was safe to turn off validation, since the method generating all the Bar
s is guaranteed to generate valid ones. 在我的用例中,关闭验证是安全的,因为生成所有Bar
的方法保证生成有效的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.