postgres中如何通过rake任务批量迁移数据?

How to migrate data in batches via rake task in postgres?

我有以下 rake 任务:

namespace :backfill do
 desc "backfill device id data"
 task device_ids: :environment do
   user_count = User.where.not(device_id: nil).count

   puts "Begin device_id backfill for #{user_count} users"

   batch_size, offset = 2000, 0
   begin
     puts "Beginning backfill batch from rows #{offset} to #{offset + batch_size} out of #{user_count} rows"

    ActiveRecord::Base.connection.execute <<-SQL
      INSERT INTO user_device_infos (user_id, user_device_id, last_login_at, created_at, updated_at)
      SELECT users.id, users.device_id, users.last_sign_in_at, current_timestamp, current_timestamp
      FROM users
      LEFT JOIN user_device_infos
      ON users.id = user_device_infos.user_id
      AND users.device_id = user_device_infos.user_device_id
      WHERE users.device_id IS NOT NULL
      AND user_device_infos.user_id IS NULL
      ORDER BY users.created_at DESC
      LIMIT #{batch_size}
      OFFSET #{offset}
    SQL
    offset += batch_size
  end until offset > user_count

  puts "backfill complete"
end

结束

此作业正在将来自用户 header table 的数据复制到设备信息子 table 中。它在生产数据库上是 运行,因此是 mini-batches 以防止锁定。它有一些问题。

  1. 它神秘地删除了记录,没有复制所有需要的数据就完成了。不知道为什么。
  2. 速度很慢。 运行 大约有 200 万条记录,需要一个多小时,我需要加快速度。
  3. 需要幂等

我怎么能

  1. 确保它 运行 仅在尚未迁移的记录上
  2. 合理地加快速度(增加批量大小,或者为 mini-batches 使用 limit/offset 以外的东西)
  3. 验证它是否已成功完成

问题是我不需要 sql 子句中的偏移量,因为左连接已经过滤掉了新记录。删除偏移既加快了工作速度又修复了工作。

将 sql 输出保存到变量并打印 puts result.cmd_status 有助于验证每个批次是否已成功完成。