批量将记录插入Active Record表

我发现我的Model.create! 当我一次添加大量记录时,语句需要很长时间才能运行。 看看ActiveRecord-Import但是它没有使用哈希数组(这是我拥有的,我认为这很常见)。 如何提高性能?

使用activerecord-import gem。 假设您正在读取CSV文件并生成Product目录,并且您希望以1000个批量插入记录:

 batch,batch_size = [], 1_000 CSV.foreach("/data/new_products.csv", :headers => true) do |row| batch << Product.new(row) if batch.size >= batch_size Product.import batch batch = [] end end Product.import batch 

感谢Chris Heald @cheald的2009年文章 ,向我展示了最好的方法是多行插入命令。

将以下代码添加到我的initializers/active_record.rb文件中,将我的Model.create!(...)调用更改为Model.import!(...)并将其Model.import!(...) 。 一些警告:

1)它不validation数据。
2)它使用SQL INSERT命令的forms,读起来像……

 INSERT INTO  (field-1, field-2, ...) VALUES (value-1-1, value-1-2, ...), (value-2-1, value-2-2, ...), ...`

…这可能不是所有数据库的正确语法,但它适用于Postgres。 为SQL版本更改适当语法的代码并不困难。

在我的特殊情况下,将19K +记录插入我的开发机器(带有8GB RAM,2.4GHz Intel Core i5和SSD的MacBook Pro)上的简单表中,使用’model.create!’从223秒开始。 使用’model.import!’到7.2秒。

 class ActiveRecord::Base def self.import!(record_list) raise ArgumentError "record_list not an Array of Hashes" unless record_list.is_a?(Array) && record_list.all? {|rec| rec.is_a? Hash } key_list, value_list = convert_record_list(record_list) sql = "INSERT INTO #{self.table_name} (#{key_list.join(", ")}) VALUES #{value_list.map {|rec| "(#{rec.join(", ")})" }.join(" ,")}" self.connection.insert_sql(sql) end def self.convert_record_list(record_list) key_list = record_list.map(&:keys).flatten.uniq.sort value_list = record_list.map do |rec| list = [] key_list.each {|key| list << ActiveRecord::Base.connection.quote(rec[key]) } list end return [key_list, value_list] end end 

我开始遇到大量记录(> 10000)的问题,所以我修改了代码,一次以1000个记录为一组。 这是新代码的链接:

https://gist.github.com/jackrg/76ade1724bd816292e4e

您还可以使用activerecord-insert_many gem。 只需制作一个对象数组!

 events = [{name: "Movie Night, time: "10:00"}, {name: "Tutoring", time: "7:00"}, ...] Event.insert_many(events) 

使用事务加速批量插入很多!

 Model.transaction do many.times{ Model.create! } end 

如果涉及多个模型,请为受影响的每个模型执行Model.transaction:

 Model1.transaction do Model2.transaction do many.times do m1 = Model1.create! m1.add_model2 end end end