5

导轨版本: 4.2.7

红宝石版本: 2.3.3

我正在运行一个 rake 任务,将数百万个对象从 CSV 和 JSON 文件格式迁移到我的 postgres 数据库中。

我试图利用activerecord-import它来加快将对象写入数据库的速度。

尽可能简化代码,前半部分处理对象类型一(来自一种数据类型),后半部分处理对象类型二。

第一个对象类型像这样迭代(为问题简化):

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真的运行(即使它一直在运行)或者如果任务挂了?

ObjectTwo我检查了 rails 控制台,我们在数据库中的 's数量似乎和以前一样。


我唯一的另一个想法是,由于我在运行之前没有打印到控制台#import(即喜欢puts "Now starting import!"),所以我没有 100% 的证据证明在数组中构建的对象已经完成。

4

1 回答 1

0

由于很难提前猜测解决您的问题需要多长时间(这取决于数据库负载、索引和许多其他因素),因此我强烈建议您分批工作。

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

所以,你可以做类似的事情:

如果 my_external_data 来自 activerecord 查询

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 是经典 ruby​​ 对象的列表

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 

使用首选解决方案 1 而不是解决方案 2,直接使用 ActiveRecord 和 find_in_batches,这将使用 OFFSET 和 LIMIT SQL 语句迭代您的数据,而不是将所有记录放在 RAM 中,然后导入它们。

如果你不能重新设计你的查询,预计运行时间是相当线性的,除非你的数据库资源没有比处理批处理所需的大得多;否则,运行时间将非常不可预测。

于 2019-11-22T17:44:10.217 回答