首页 > 解决方案 > Ruby On Rails = 将 ActiveRecord 与包含数千条记录的数组进行比较

问题描述

我有一个包含大约 500,000 条记录(csv_data)的传入 CSV。想要将其与存储在 ActiveRecord (PreviousData) 中的先前数据进行比较。

目前有这个,但失败了,因为它需要很长时间来比较大型数据集。我将如何优化它以处理更大的数据集?

added = csv_data.select{|item| !PreviousData.where(iden: item[:iden]).exists?}

标签: ruby-on-railsruby

解决方案


您可以使用Enumerable#each_slice分块进行:

exists = csv_data.each_slice(1000).map do |chunk|
  PreviousData.where(id: chunk.map { |item| item[:iden] })
              .pluck(:id)
end.flatten

这将在 CSV 文件中每 1000 行执行一次 SQL 查询,而不是每行一次,这将产生巨大的性能差异。您当然可以使用批量大小来调整内存消耗与数据库查询的数量。

with_index如果要跟踪当前所在的切片,也可以使用:

exists = csv_data.each_slice(1000).with_index.map do |chunk, index|
  puts "Importing chunk #{index}"
  PreviousData.where(id: chunk.map { |item| item[:iden] })
              .pluck(:id)
end.flatten

如果您正在做的是从 CSV 文件创建记录,您将需要考虑使用 UPSERT(如果可用)并将创建包装在单个事务中或执行批量 INSERT/UPSERT。


推荐阅读