Rails版本: 4.2.7
Ruby版本: 2.3.3
我正在运行rake任务,将数百万个对象从CSV和JSON文件格式迁移到我的postgres数据库中。
我试图利用activerecord-import
来加速将对象写入数据库。
尽可能简化代码,前半部分处理对象类型1(来自一种数据类型),后半部分处理对象类型2。
第一个对象类型迭代如此(对于问题简化):
importing_object_one_array = []
my_external_data.each do |element|
new_element = ObjectOne.new(
title: element[0],
body: element[1]
)
importing_object_one_array << new_element
end
ObjectOne.import importing_object_one_array, validate: false
大约有250,000个对象,并且没有任何问题,我已经在控制台中进行了检查,并成功编写了对象。
但是,对象类型2具有相当多的额外对象,每个对象的大小和设计大致与对象类型1相同。
其中大约有4,040,000个。
等待ObjectTwo.import
运行需要多长时间?我们现在已经好几个小时了。
或者,从调试的角度来看(因为我真的不想重新运行这个rake任务,除非我绝对必须这样做),看看ObjectTwo.import
是否真的是什么样的脚本或策略才有用/ strong>当前正在运行(即使它正在运行)或者任务是否挂起?
我检查了rails控制台,我们看起来仍然和以前在数据库中的ObjectTwo
数量相同。
我唯一的另一个想法是,因为我在运行#import
之前没有打印到控制台(即像puts "Now starting import!"
)我没有100%证明数组中的对象构建已完成。
答案 0 :(得分:0)
由于很难预先估计解决问题所需的时间(取决于数据库负载,索引和许多其他因素),因此我强烈建议您分批工作。
此外,这将使您的数据库面临一个非常大的请求,这可能会耗尽其RAM,CPU和网络资源。
因此,您可以执行类似的操作:
total_records_count = large_query.count
large_query.find_in_batches(batch_size: 1000) do |batch|
puts("Progress: #{100*processed_records/total_records_count}%")
ObjectOne.import importing_object_one_array, validate: false
end
total_records_count = guess_number_of_records_to_process
large_array.in_groups_of(1000) do |batch|
puts("Progress: #{100*processed_records/total_records_count}%")
ObjectOne.import importing_object_one_array, validate: false
end
与解决方案2一起使用优先解决方案1,直接与ActiveRecord和find_in_batches一起使用,这将使用OFFSET和LIMIT SQL语句遍历数据,而不是将所有记录放入RAM,然后将它们导入。
如果您无法重新设计查询,则可以期望运行时间非常线性,除非您的数据库资源没有比处理批处理所需的资源大很多;否则,运行时间将是不可预测的。