QA@IT

Railsで大量のデータに対して、パッチを当てるには?

4174 PV

現在Rails3.2を使って開発しているのですが、大量のデータを更新する処理を書いているのですが、うまくいきません。

具体的に例を挙げて説明させていただきます。

まずデータが40_000件ほどあります。

これに対してあるフィールドの値を全て、hogeに変更したいと考えました。
そこで以下の様に書いたrbファイル(Hoge.rb)を用意しました。

Model.where(:id => 1..40000).find_each(batch_size: 40_010) do |model|
  model.hoge = "hoge"
  model.save!
end

次にこのrbファイルに対して以下のコマンドを実行することで、このプログラムを実行しました。

rails runner Hoge RAILS_ENV=production

その後、rails c productionでデータを確認したのですが、hogeに更新されていませんでした。

このプログラムのどこが悪いどうこうもあるのですが、そもそもこのような大量なデータに対して上記のような方法を取るのは正しいのか不安に思いました。
そこで改めて質問なのですが、この方法はあっていますか?またあっているとしたら、このプログラムでなぜデータが更新されないんでしょうか?

回答

下記のコマンドを実行してみるとわかりますが、これだと development 環境で実行されてしまいます。

$ rails runner 'puts Rails.env' RAILS_ENV=production
development

下記のように -e オプションで指定するのが正しいやり方です。

$ rails runner -e production 'puts Rails.env'
production

ちなみに RAILS_ENV=production rails runner ... のように環境変数で指定しても問題はなさそうです (たぶん)。

参考: The Rails Command Line — Ruby on Rails Guides

そもそもこのような大量なデータに対して上記のような方法を取るのは正しいのか不安に思いました。

こういったケースでfind_each メソッドを使うのは正しいですが、batch_size オプションの値に問題があります。batch_size オプションは、一度に DB から取ってくるレコードの数を指定するものなので、対象とするすべてのレコードの数より小さい値を指定しないと意味がありません。

指定しない (1000 件になる) か、メモリのサイズなどを考慮して適当な値に調整する必要があります。

参考: ActiveRecord::Batches

編集 履歴 (0)
  • お返事ありがとうございます。

    なるほど、envの指定の仕方が間違っていたんですね。お恥ずかしい限りです。

    batch_sizeを指定するのはよくなかったんですね。自分はうっかり発行されたSQLのlimitが1000ついてるから、limitを広げなくてはいけない。と思ったんですが、1000件ずつlimitをつけてくれるという意味だったんですね。

    ありがとうございました。
    -
  • アカウント間違えました><。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。