update_all
300,000 レコードの列をすべてさまざまな値で更新したい場合、どのように使用できますか?
私がやりたいことは次のようなものです:
Model.update_all(:column => [2,33,94,32]).where(:id => [22974,22975,22976,22977])
しかし、残念ながらこれは機能せず、300,000 エントリの場合はさらに悪化します。
update_all
300,000 レコードの列をすべてさまざまな値で更新したい場合、どのように使用できますか?
私がやりたいことは次のようなものです:
Model.update_all(:column => [2,33,94,32]).where(:id => [22974,22975,22976,22977])
しかし、残念ながらこれは機能せず、300,000 エントリの場合はさらに悪化します。
あなたの質問に対する簡単な答えは、できません。
update_all のポイントは、すべてのレコードの列に同じ値を割り当てることです (条件が指定されている場合は一致します)。便利な理由は、単一の SQL ステートメントでそれを行うためです。
正しさについてのシメの答えに同意します。ただし、 n SQL 呼び出しが生成されます。ですから、あなたの問題には、あなたが私たちに伝えていない何かがあるかもしれません。おそらく、その値で更新する必要があるオブジェクトに対して update_all を呼び出して、可能な値ごとに反復することができます。次に、適切なハッシュを作成するか、さらに良いことに、条件がモデル自体の何かに基づいている場合は、その条件を update_all に渡すことができます。
これが私の2020年の答えです:
最も支持された答えは間違っています。著者自身が述べているように、n
行ごとに 1 つずつ、SQL クエリをトリガーします。
2番目に支持された回答は、gem「activerecord-import」を提案しています。これが進むべき道です。ただし、これは ActiveRecord モデルをインスタンス化することによって行われます。また、このような gem のビジネスを行っている場合は、おそらく極端なパフォーマンスを求めているでしょう (いずれにせよ、これは私たちの場合でした)。
これが私たちがしたことです。まず、 hash の配列を作成します。各ハッシュにid
は、更新するレコードの とその他のフィールドが含まれています。
例えば:
records = [{ id: 1, name: 'Bob' }, { id: 2, name: 'Wilson' },...]
次に、次のように gem を呼び出します。
YourModelName.import(records, on_duplicate_key_update: [:name, :other_columns_whose_keys_are_present_in_the_hash], validate: false, timestamps: false)
説明:
on_duplicate_key_update
つまり、データベースが主キーで競合を検出した場合 (既存のレコードの更新について話しているため、すべての行で競合が発生します)、失敗せず、代わりにその配列で渡す列を更新します。
そうしないとvalidate false
(デフォルトは true)、行ごとに新しいモデル インスタンスをインスタンス化しようとし、検証のために失敗する可能性があります (ハッシュには部分的な情報しか含まれていないため)。
timestamp false
もオプションですが、そこにあることを知っておくとよいでしょう。