##1. 「N+1問題」とは??
アソシエーションを利用した際に、データベースへのアクセス回数が多くなってしまう問題を「N+1問題」といいます。
例えば1つのツイート投稿(tweet)は1人のユーザー(user)とアソシエーションで結びついているとします。そして、データベースから全てのツイート投稿を取得するとアソシエーションによりユーザー情報も取得しようとします。
この時、次のコードだとターミナルではこのようなログを示します。
class TweetsController < ApplicationController
def index
@tweets = Tweet.all
end
end
水色の箇所がTweetsテーブルとUsersテーブルにアクセスしているログです。
Tweetsテーブルに対しては1回で全ての情報を取得していますが、Usersテーブルには6回アクセスしています。
(このときTweetsテーブルに存在するTweetのレコードは6つです。)
取得したTweet1つ1つに対して、アソシエーションを使ってユーザーのレコードを取得する処理を繰り返していることを示しています。つまり100個のツイート投稿を取得すると、100回Usersテーブルにアクセスすることになり、データ取得に時間がかかります。その結果、アプリケーションのパフォーマンスが著しく下がることになります。これが「N+1問題」です。これを解決するためには、includesメソッドを利用します。
##2. includesメソッド
モデル名.includes(:アソシエーションで紐付くモデル名)
includesメソッドは、引数に指定された関連モデルを1度のアクセスでまとめて取得するメソッドです。このメソッドを用いて以下のようにコードを書き換えます。
class TweetsController < ApplicationController
def index
@tweets = Tweet.includes(:user)
end
end
結果、水色の箇所が2つに変わりました。Tweetsテーブルに対して1回、Usersテーブルに対しても1回のアクセスで全ての情報を取得できました。
##3. さいごに
私自身、今まで勉強する中で膨大なデータの使用を想定した開発をしていませんでした。そのため「N+1問題」を勉強して、アプリケーションのパフォーマンスを意識した開発する重要性を感じました。この記事を読んで、内容が良かったらLGTMお願いします!また、ご意見があれば是非コメントもお願いします。