【问题标题】:Inserting a 300M row dataset into PostgreSQL using ActiveRecord使用 ActiveRecord 将 300M 行数据集插入 PostgreSQL
【发布时间】:2017-05-27 07:05:24
【问题描述】:

我有一个包含 3 亿个条目的数据集,我需要将其插入 PostgreSQL 数据库。数据采用 Amazon S3 上的 gzip 压缩 JSON 行文件的形式。每个文件有 50k JSON 行,每个 JSON 行大约 35kb。

现在我正在 Sidekiq 上为 S3 (~5500) 上的每个 JSON 行文件创建一个作业。 我在 Heroku 上有工作人员(标准 2x 工作人员)处理这些文件。工作人员下载 JSON 行文件,解析行并开始通过 ActiveRecord 将它们持久化到数据库(一次执行 1000 个事务)。现在我发现每个工人每分钟可以坚持大约 2500 行。我还发现,如果我显着增加工作人员的数量(例如 50 个),每个工作人员每分钟插入的条目数会下降(我的数据库应该能够处理多达 200 个连接)。

我希望我能做得更快。任何提高性能的指针?

这是 Sidekiq 作业中的逻辑:

# entries is an array of 50k strings, where each string is a JSON object
entries = EntriesDataService.get_entries(s3_url)

entries.each_slice(1000) do |chunk|
 ActiveRecord::Base.transaction do
   chunk.each {|p| Model.from_json_string(p)}
 end
end

【问题讨论】:

  • 我知道这个问题已经过时了,但是使用原始 sql 并完全绕过 ActiveRecord 怎么样?对于您正在处理的记录数量,ActiveRecord 是瓶颈......我一口气给了 postgres 500,000,它保存了所有记录,只有一个持久化。所以postgres可以一次性处理大量数据...

标签: sql ruby-on-rails postgresql activerecord sidekiq


【解决方案1】:

您可以像这样为每个块执行多重插入:

entries.each_slice(1000) do |chunk|
  values = get_values_from_chunk(chunk)
  query = "INSERT INTO table (col1, col2, ...) VALUES #{values}"
  ActiveRecord::Base.connection.execute(query)
end

get_values_from_chunk 方法必须以字符串形式返回一组值,例如:

values = "(col1v1, col2v1, ...), (col1v2, col2v2, ...), ..., (col1vn, col2vn, ...)"

通过这种方式,插入将得到极大的改善。

【讨论】:

  • 这是我找到的最快的方法。仍然比我预期的要慢得多。我很惊讶我很难找到更多关于批量插入的资源(大约数千万)。
猜你喜欢
  • 2012-04-03
  • 1970-01-01
  • 1970-01-01
  • 2021-05-20
  • 1970-01-01
  • 2021-10-03
  • 2021-04-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多