railsのn+1問題をincludesで対策

はじめに

railsアプリケーションで起こる、n+1問題includesを使って対策する方法について

n+1問題とは

n+1問題とは、1回のアクセスでいいのに何回もデータベースにアクセスしてしまい、

それによってページの読み込み速度の低下などにつながってしまうことです。

例えば、userとpostが1対多数の関係にあるとき、

@users = User.all

@users.each do |user|
puts user.post.content

上記のコードが実行されると、

1:まずuserの一覧を取得するためデーターベース(user)へアクセスします。

2:ローカル変数userのidに対応するpostを取得するためにデータベース(post)にアクセスします。

3:2の処理をuserの数だけ繰り返してしまう。

→つまり、ユーザーの数だけn回データベース(post)にアクセスしてしまうわけです。

どちらかというと、1+n問題です。

n+1問題の解決法

解決法はいくつかあるのですが、ここでは「includes」を使う方法をご紹介します。

仮にAモデルとBモデルがある場合、

A.includes(:B).all

こうすることで、Aに関連するBも取得できるようになります。

@users = User.includes(:post).all  
# ユーザーが3人の場合、ここでユーザー3人に関連するpostのデータもまとめて取得してきてくれる。

@users.each do |user|
puts user.post.content

eachの前にpostの情報も取得してきてくれるため、n+1問題が起こらなくなります。

includesなしの場合だと、データベースに4回アクセスする(ユーザーテーブルx1回とポストテーブルx3回)のに対し、

includesありの場合だと2回で取得できるようになります。

なので取得するデータが多いほど、includesの効果は顕著になります。