0
Help us understand the problem. What are the problem?

posted at

updated at

[Rails][Ruby] update_allとwhereを使用するときに気をつけること

はじめに

未経験からエンジニアに転職して、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 を自動更新しない

参考

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
0
Help us understand the problem. What are the problem?