LoginSignup
11
8

More than 5 years have passed since last update.

Rails ActiveRecordのアンチパターン 初心者→中級者へのSTEP22/25

Posted at

Rails ActiveRecordのアンチパターン

はじめに

急にスケジュールが詰め詰めになったので、残り4日とわずかですが、今回は少なめです。すみません...
頑張ります。
今回はActiveRecordにおけるアンチパターンについて。パフォーマンスを落とすようなコードを書かないようにアンチパターンを日々、覚えるようにしましょう。

All Each Pattern

User.allなどでレコードを全取得してそこからeachで回すパターン。

User.all.each do|user|
  if user.created_at >= Date.new(2018)
    user.point += 100
    user.save
  end
end

2018年以降に登録してくれたユーザにポイントをプレゼントしよう的なコード(ほぼ参考元のコードです。すみません)

ダメなとこ
1,Userの全件取得でメモリを圧迫。
2,eachメソッドにより取得したユーザー全件を一気にメモリに展開してから処理するので、こちらもよろしくない。

改善策
1,そもそも全件取得する必要がない。whereを使って取得件数を下げる。
2,find_eachメソッドを使って、分割して処理する。(find_eachメソッドはeachメソッドと違って、一気にではなく分割して処理する。)

改善後

User.where("created_at >= ?", Date.new(2018)).find_each do |user|
    user.point += 100
    user.save
end

よくなりました...と思いきや、まだ問題があります。

N+1 update queries pattern

前にN+1問題は書きましたね。↓
RailsのN+1問題の解決方法 初心者→中級者へのSTEP9/25

似たような感じの問題です。1回のselectに対し、N回のupdateが起きています。1回にしましょう。
update_allを使う。

再改善後

User.where("created_at >= ?", Date.new(2018)).update_all("point = point + 100")

以前書きましたが、update_allはバリデーションをしませんので今回は問題ないですが、パフォーマンスが上がる!と言っってむやみに使ってはダメです。

これでパフォーマンスがぐぐっと上がるはずです。

まとめ

なんかほぼ自分のブログみたいになってきたこのカレンダー。お家がゴタゴタして書く暇あるか微妙ですが、残り数日休まず記事をあげたいです。今回のアンチパターンは参考元のスライドが非常にわかりやすいです。興味持ったらぜひそちらを読んでください。他の例も載せてくださってます。

参考にしたの

ActiveRecordデータ処理アンチパターン
https://speakerdeck.com/toshimaru/active-record-anti-patterns?slide=26

簡単に始められるRailsパフォーマンス改善
https://qiita.com/yu-croco/items/d7a39b34036d638c5026

11
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
8