あゆの塩焼きブログ

【Rails】ループ内でメモリ処理を活用する

Agenda目次
  • ・🚀Railsでループ内のメモリ絞り込みを活用するテクニック
  • ・📋 メモリ内で処理するための重要テクニック一覧
  • ・🛠️ それぞれのテクニックの詳細とユースケース
  • ・💡 自分が助けられた実体験
  • ・🎯 まとめ

🚀Railsでループ内のメモリ絞り込みを活用するテクニック

Rails開発者が一番頭を抱えるのが、N+1問題をどう避けるかでしょう。

定石はeager loadingを使用することだと思いますが、それだけでは防げないケースも多々あると思います。

そういった際に、メモリ内処理というのを活用できる選択肢を持っておくと、問題解決の幅が上がると思っています。

私自身、実際のプロジェクトで大量のデータを扱う際に、メモリ内処理を利用して助かった経験があります。

今回はその経験を踏まえて、「ループ内でのメモリ絞り込み」のテクニックをいくつか調査・整理してみました。

📋 メモリ内で処理するための重要テクニック一覧

まず、実際の現場で役立ちそうなテクニックは次の通りです。

テクニック 内容
where(...).to_a 事前にまとめて取得してメモリ展開
select { ... } メモリ内でのデータ絞り込み
group_by(&:key) ループ前に分類して高速アクセス可能に
index_by(&:id) IDなどをキーにしてハッシュで高速アクセス

🛠️ それぞれのテクニックの詳細とユースケース

1. 🔹 where(...).to_a

クエリの結果を一度に取得し、メモリ内に展開します。ループ内で何度もデータを取りに行くことを避けられます。

実例コード

posts = Post.where(published: true).to_a

2. 🔹 select { ... }

メモリ内にあるデータ群から条件に合ったデータを絞り込みます。非常に高速で、追加クエリは発生しません。

実例コード

published_posts = posts.select { |post| post.published_at > 1.week.ago }

3. 🔹 group_by(&:key)

取得したデータをループ前にグルーピングすることで、データへのアクセスをハッシュで高速化できます。

実例コード

grouped_posts = posts.group_by(&:user_id)
users.each do |user|
  user_posts = grouped_posts[user.id] || []
  puts "#{user.name} は #{user_posts.count}件の投稿があります"
end

4. 🔹 index_by(&:id)

データをIDでハッシュ化し、高速に1対1でアクセスできます。単一データの迅速な参照に役立ちます。

実例コード

users_by_id = User.all.index_by(&:id)
post_author = users_by_id[post.user_id]

💡 自分が助けられた実体験

以前、ユーザーごとの大量投稿データを表示する機能を開発した際、selectを使ったメモリ処理で劇的にパフォーマンスが改善しました。

具体的には、

  • 改善前:ループ内で毎回クエリが発生(N+1問題)
  • 改善後:一度メモリ展開後、selectを用いて絞り込み

という流れで、DBへの負荷が激減し、ユーザー体感速度も大幅に向上しました。(実に200倍近い処理速度の改善!!)

🎯 まとめ

ループ内でのメモリ処理は、実装時に特に悩まされやすいポイントです。
今回紹介したテクニックは実際に試してみたものもあるので、ぜひプロジェクトで活用してみてください。

Loading...