19

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

4

6 回答 6

23

使用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
于 2013-03-10T02:21:44.090 回答
12

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

将以下代码添加到我的initializers/active_record.rb文件中,将我的Model.create!(...)调用更改为Model.import!(...)然后消失。几个警告:

1)它不验证数据。
2) 它使用 SQL INSERT 命令的形式,读起来像 ...

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

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

在我的特殊情况下,使用“model.create!”将 19K+ 记录插入我的开发机器(配备 8GB RAM、2.4GHz Intel Core i5 和 SSD 的 MacBook Pro)上的一个简单表中,从 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
于 2013-03-10T01:17:10.810 回答
5

我开始遇到大量记录(> 10000)的问题,因此我修改了代码以一次处理 1000 条记录。这是新代码的链接:

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

于 2014-05-16T18:16:19.237 回答
1

对于 Rails 6.x 使用insert_all

于 2021-02-22T23:11:48.630 回答
1

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

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

Event.insert_many(events)
于 2015-12-18T15:46:05.607 回答
0

使用事务可以大大加快批量插入的速度!

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
于 2016-02-11T17:17:12.660 回答