はじめに
未経験からエンジニアに転職して、2ヶ月ほど経つエンジニアです。
業務にあたりながらも、小規模なアプリを作って楽しんでいます。
今回は大量のレコードをまとめて更新するときに重宝する update_all についてです。
結論
update_all を使用するときはクエリの実行タイミングに注意しよう。
update_all とは
条件に一致するレコードをSQLを直接実行して全て更新
updated_atとupdated_onは更新されない
バリデーションやトランザクションを無視する点も注意が必要です。
クエリキャッシュのタイミングに注意
def update_user_data
#このタイミングではクエリは走らない
users = User.where(id: XXX, status: XXX, ...)
#上記 where と組み合わせて UPDATE users ... FROM ... WHERE ... が走る
users.update_all(
status: XXX,
updated_at: Time.current
)
# この時、usersは空になってしまう (SELECT * FROM users WHERE ... が走る)
# p users = []
users.each do |i|
...
end
end
そもそもupdate_allが必要なのか検討してみてください。
update_allを使用したい場合は以下のようにすることで解決できます。
def update_user_data
#このタイミングではクエリは走らない
users = User.where(id: XXX, status: XXX, ...)
# users を保存しておく(ActiveRecord:Relationではない状態にして保存)
users_before_update_all = users.to_a
#上記 where と組み合わせて UPDATE users ... FROM ... WHERE ... が走る
users.update_all(
status: XXX,
updated_at: Time.current
)
# 保存した方を使う
users_before_update_all.each do |i|
...
end
end
まとめ
update_allは
複数のレコードを一括で更新できます。
DBへの負荷を軽減できます。
一方で、下記のような注意するべき点があります。
- バリデーションを実行しない
- トランザクションを実行しない
- 更新前の状態に依存する
- updated_at を自動更新しない
参考