Ruby on Rails - лучший способ обновления 100 тыс. Записей - PullRequest
0 голосов
/ 09 мая 2018

Я нахожусь в ситуации, когда мне нужно обновить более 100 тыс. Записей в базе данных наиболее эффективным способом. См. Мой код ниже:

namespace :order do
  desc "update confirmed at field for Payments::Order"
  task set_confirmed_at: :environment do
    puts "==> Updating confirmed_at for orders starts ...".blue
    Payments::Order.find_each(batch_size: 10000) do |orders|
      order_action = orders.actions.where("sender LIKE ?", "%ConfirmJob%").first if orders.actions
      if !order_action.blank?
        orders.update_attribute(:confirmed_at, order_action.created_at)
        puts "order id = #{orders.id} has been updated.".green
      end
    end
    puts "== completed ==".blue
  end
end

Здесь я делю записи на 10000 каждого размера пакета, а затем пытаюсь обновить запись на основе некоторых условий, чтобы кто-нибудь мог предложить мне более эффективный способ выполнить ту же задачу.

Заранее спасибо!

Ответы [ 2 ]

0 голосов
/ 09 мая 2018

Вы делаете Payments::Order.find_each, поэтому ваше решение будет зацикливаться для каждого Payment::Order, когда вы хотите зациклить только те, которые имеют actions.server like '%ConfirmJob%', поэтому я пойду с этим решением:

Payments::Order
  .includes(:actions)
  .joins(:actions)
  .where("actions.server like '%?%'", "ConfirmJob")
  .find_each do |order|
    order_action = order.actions.first
    order.update!(confirmed_at: order_action.created_at)
end
0 голосов
/ 09 мая 2018

Вы можете попробовать update_all:

Payments::Order.joins(:actions).where(Payment::OrderAction.arel_table[:sender].matches("%ConfirmJob%")).update_all("confirmed_at = actions.created_at")

Итак, ваш код будет выглядеть так:

namespace :order do
  desc "update confirmed at field for Payments::Order"
  task set_confirmed_at: :environment do
    puts "==> Updating confirmed_at for orders starts ...".blue
    Payments::Order.joins(:actions).where(Payments::OrderAction.arel_table[:sender].matches("%ConfirmJob%")).update_all("confirmed_at = actions.created_at")
    puts "== completed ==".blue
  end
end

Обновление : Я исследовал проблему и обнаружил, что массовое обновление с объединенной таблицей является долгосрочной проблемой в рельсах Поскольку set part использует строковый параметр, я предлагаю добавить туда предложение from.

namespace :order do
    desc "update confirmed at field for Payments::Order"
      task set_confirmed_at: :environment do
        puts "==> Updating confirmed_at for orders starts ...".blue
          Payments::Order.joins(:actions).
                where(Order::Action.arel_table[:sender].matches("%ConfirmJob%")).
                update_all("confirmed_at = actions.created_at FROM actions")
        puts "== completed ==".blue
      end
    end
...