我应该允许activerecord-import运行多长时间?

时间:2017-02-26 15:06:02

标签: ruby-on-rails ruby activerecord activerecord-import

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%证明数组中的对象构建已完成。

1 个答案:

答案 0 :(得分:0)

由于很难预先估计解决问题所需的时间(取决于数据库负载,索引和许多其他因素),因此我强烈建议您分批工作。

此外,这将使您的数据库面临一个非常大的请求,这可能会耗尽其RAM,CPU和网络资源。

因此,您可以执行类似的操作:

如果my_external_data来自活动记录查询

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 

如果my_external_data是经典红宝石对象的列表

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,然后将它们导入。

如果您无法重新设计查询,则可以期望运行时间非常线性,除非您的数据库资源没有比处理批处理所需的资源大很多;否则,运行时间将是不可预测的。