我发现,当我一次添加大量记录时,我的Model.create!语句运行时间很长。查看了ActiveRecord-Import,但它不能处理哈希数组(我有哈希数组,我认为这是很常见的)。我如何提高性能?
Model.create!
70gysomp1#
使用activerecord-import gem。假设您正在阅读一个CSV文件并生成一个Product目录,并且希望以1000个为一批插入记录:
Product
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
7rtdyuoh2#
感谢Chris Heald @cheald编写的2009 article,with向我展示了最好的方法是多行插入命令。在我的initializers/active_record.rb文件中添加了以下代码,将我的Model.create!(...)调用更改为Model.import!(...),然后就可以了。1)它不会验证数据。2)它使用SQL INSERT命令的格式,如下所示...
initializers/active_record.rb
Model.create!(...)
Model.import!(...)
INSERT INTO <table> (field-1, field-2, ...) VALUES (value-1-1, value-1-2, ...), (value-2-1, value-2-2, ...), ...`
...这可能不是所有数据库的正确语法,但它适用于Postgres。为您的SQL版本修改适当语法的代码并不困难。在我的特殊情况下,在我的开发机器(配备8 GB RAM、2.4GHz英特尔酷睿i5和SSD的MacBook Pro)上向一个简单的表中插入19 K+条记录的时间从使用'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
dgsult0t3#
我开始遇到大量记录(〉10000)的问题,所以我修改了代码,一次可以处理1000条记录。下面是新代码的链接:https://gist.github.com/jackrg/76ade1724bd816292e4e
sc4hvdpw4#
对于Rails 6.x,请使用insert_all。
x33g5p2x5#
您也可以使用activerecord-insert_many gem。只需创建一个对象数组!
events = [{name: "Movie Night", time: "10:00"}, {name: "Tutoring", time: "7:00"}, ...] Event.insert_many(events)
bvjveswy6#
使用事务可以大大加快批量插入的速度!
Model.transaction do many.times{ Model.create! } end
如果涉及多个模型,请为每个模型执行一个Model.事务,该事务受以下因素影响:
Model1.transaction do Model2.transaction do many.times do m1 = Model1.create! m1.add_model2 end end end
2ekbmq327#
https://stackoverflow.com/a/15318202/9732392这个答案解释得很好,但在我看来,如果我们使用数组而不是下面的Product.new(row),它可能会更快
Product.new(row)
batch,batch_size = [], 1000 CSV.foreach("/data/new_products.csv", :headers => true) do |row| batch << [row[:part_number], row[:item_name], row[:cost]] if batch.size >= batch_size product_columns = [:part_number, :item_name, :cost] Product.import product_columns, batch, on_duplicate_key_update: {conflict_target: [:id], columns: [:part_number, :item_name, :cost]} batch = [] end end Product.import product_columns, batch, on_duplicate_key_update: {conflict_target: [:id], columns: [:part_number, :item_name, :cost]} if batch.present?
更多信息请阅读?https://github.com/zdennis/activerecord-import
7条答案
按热度按时间70gysomp1#
使用activerecord-import gem。假设您正在阅读一个CSV文件并生成一个
Product
目录,并且希望以1000个为一批插入记录:7rtdyuoh2#
感谢Chris Heald @cheald编写的2009 article,with向我展示了最好的方法是多行插入命令。
在我的
initializers/active_record.rb
文件中添加了以下代码,将我的Model.create!(...)
调用更改为Model.import!(...)
,然后就可以了。1)它不会验证数据。
2)它使用SQL INSERT命令的格式,如下所示...
...这可能不是所有数据库的正确语法,但它适用于Postgres。为您的SQL版本修改适当语法的代码并不困难。
在我的特殊情况下,在我的开发机器(配备8 GB RAM、2.4GHz英特尔酷睿i5和SSD的MacBook Pro)上向一个简单的表中插入19 K+条记录的时间从使用'model.create!'的223秒缩短到使用'model.import!'的7.2秒。
dgsult0t3#
我开始遇到大量记录(〉10000)的问题,所以我修改了代码,一次可以处理1000条记录。下面是新代码的链接:
https://gist.github.com/jackrg/76ade1724bd816292e4e
sc4hvdpw4#
对于Rails 6.x,请使用insert_all。
x33g5p2x5#
您也可以使用activerecord-insert_many gem。只需创建一个对象数组!
bvjveswy6#
使用事务可以大大加快批量插入的速度!
如果涉及多个模型,请为每个模型执行一个Model.事务,该事务受以下因素影响:
2ekbmq327#
https://stackoverflow.com/a/15318202/9732392这个答案解释得很好,但在我看来,如果我们使用数组而不是下面的
Product.new(row)
,它可能会更快更多信息请阅读?https://github.com/zdennis/activerecord-import