大量データを更新する場合はループではなくバルク操作を使うべき

2025/09/01

理由

  • ループで1件ずつ更新すると、レコード数分だけSQLクエリが発行されるため、処理速度が遅くなる。
  • データベースやアプリケーションサーバーに大きな負荷がかかり、パフォーマンスが著しく低下する恐れがある。
  • バルク操作(例:update_all)は1回のSQLクエリで複数レコードをまとめて更新できるため、高速かつ効率的。

ループで更新した場合の影響

  • データ数が多いほど実行時間が長くなる。
  • ネットワークやDBサーバーへの負荷が増大し、障害やタイムアウトのリスクが高まる。
  • 他の処理やユーザーへの影響が出やすい(全体のレスポンス低下や遅延など)。

悪い例(ループで1件ずつ更新)

User.where(active: false).find_each do |user|
  user.update!(active: true)
end

良い例(バルク操作でまとめて更新)

User.where(active: false).update_all(active: true)

注意点

  • update_allなどのバルク操作は、バリデーションやコールバックが実行されない(モデルレイヤーを経由しない)ため、必要な処理があれば事前に考慮する。
  • レコードごとに異なる複雑な処理が必要な場合や、バリデーション・コールバックが必須な場合は、ループで個別処理するケースもある。
  • バルク処理時は、どのレコードがどのように更新されたかの追跡やログ出力が難しい場合がある。