2017-08-18 6 views
2

Ruby on Railsアプリケーションには100,000,000人のユーザーがいます。モデル上にデータという名前の列があります。これは新しいフィールドに保存することでバックアップしたいJSONオブジェクトを含むJSONフィールドです。ユーザーオブジェクトの縮尺を更新するにはどうすればよいですか?

users = User.all 
users.each do |user| 
    user.data_backup = user.data 
    user.save 
end 

をして、新しい列に既存のデータを保存します。私は、1,000人のユーザーを持っていた場合

私は単純に実行することができます。しかし、これは潜在的に多くのユーザーと永遠にかかる可能性があります。 100,000,000人以上のユーザーがいる場合、モデルのあらゆる分野を更新するための適切かつ/または最も効率的な方法は何ですか?

+1

あなたは私はあなたが最初の場所でこれをしたいと思いますなぜわからない100MMユーザーがいる場合。これにより、すぐにテーブルのストレージ要件が倍増します。バックアップデータを使ってセカンダリテーブルを作成することをお勧めします。そのため、*ユーザーレコードが取得されるたびにこれを読み込む必要はありません。変更を元に戻すか元に戻すことができるように、何らかの種類のバージョン管理システムを作成しようとしていますか? – tadman

答えて

0

はSQLで行うことができる:

sql = "UPDATE users SET data_backup = data" 
ActiveRecord::Base.connection.execute(sql) 

またはupdate_all:レコードの数が多い場合は

User.update_all('data_backup = data') 
+1

あなたの別のフォームは動作しません。 'data'は定義されていない変数で、たとえそれがあったとしても、すべての単一ユーザーを同じ値に設定しています。最初の 'update_all'は正しいです。 – tadman

+0

私は代わりを書いていませんでした。私はそれを削除しました。 – moveson

2

、方法

User.find_in_batches(batch_size: 1000) do |users| 
    users.each do |user| 
    user.data_backup = user.data 
    user.save 
    end 
end 
+1

find_eachはここにブロックを保存します:-) –

0

をfind_in_batchs使用しようとする私たちはシナリオを持っていました大量のレコードを繰り返し処理し、それぞれの通知を呼び出す必要があります。

User.all.each do |user| 
    NewsMailer.weekly(user).deliver_now 
end 

上記のコードは、私たちの最終目標を満足するものです。 しかし、このアプローチは、テーブルサイズが増加するにつれてますます非実用的になります。なぜなら、User.all.eachはアクティブレコードに1回のパスでテーブル全体をフェッチし、行ごとにモデルオブジェクトを作成し、モデルオブジェクトの配列全体をメモリ。実際、多数のレコードがある場合、コレクション全体が利用可能なメモリの量を超えている可能性があります。

一括更新を実行する必要があるシナリオでは、Railsは、レコードをメモリーに適したバッチに分割して処理することで、この問題に対処する方法を提供します。

  1. find_each、レコードのバッチを取得した後、個々にモデルとしてのブロックに各レコードをもたらします。あなたは同じ処理キューを扱う複数の労働者を望んでいた場合

    User.find_each(batch_size: 5000) do |user| 
         NewsMailer.weekly(user).deliver_now 
    end 
    

    または

別の例は次のようになります。それぞれの作業者に適切な:startと:finishオプションを設定することで、各作業者に10000レコードを処理させることができます。

User.find_each(start: 2000, finish: 10000) do |user| 
    NewsMailer.weekly(user).deliver_now 
end 
  • find_in_batchesは、レコードのバッチを取得した後、モデルの配列としてブロックにバッチ全体をもたらします。 find_in_batchesメソッドはfind_eachと似ています。両方ともレコードのバッチを取得するためです。違いは、find_in_batchesは、個別にではなく、モデルの配列としてブロックにバッチを生成することです。

    ユーザー。find_in_batches do |ユーザー|

    NewsMailer.weekly(user).deliver_now 
    

    エンド

  • 関連する問題