#RailsのN+1問題の解決方法
はじめに
RDM楽しかったです。後々、記事にしてみせます。二日酔いです。頑張って書きます。
今回はパフォーマンスを悪くするN+1問題の解決方法についてです。
##N+1問題とは##
コードをみた方が早いかもしれません。下記コードをみてください。
class User < ApplicationRecord
has_one :blog
end
class Blog < ApplicationRecord
belongs_to :user, foreign_key: "user_id"
end
わかりすいようにユーザーがブログを一つ持つようなリレーションモデルを考えます。
user#indes
にて各ユーザーの名前とそのユーザーのブログ名を表示するようにします。
- @users.each do |user|
= user.name
= user.blog.name
各ユーザーごとにBlogテーブルにアクセスしています。これがもしユーザー数が千、万、10万...となってくると非常にパファーマンスが悪いです。これがN+1問題です。(user一覧表示の為のデータ取得のSELECTが1
、各ユーザのブログを取得する為のSELECTがN
となります)
パフォーマンス向上の為、ブログテーブルへのSELECTを一回にしたいです。
##解決方法のincludes
解決策は簡単で、includes
を使うだけです、includes
メソッドは関連するテーブルをまとめて取得してくれます。
- @user_index.includes(:blog).each do |user|
= user.blog.name
これでブログテーブルへのSELECTが1つになりました!!N+1問題は解決です。
※今回は1対1の関連モデルを例に説明しましたが、N対1対Nの場合、など状況によってincludes
の使い方を少し考える必要があります。とりあえすincludes
入れればいいや、ではなくログをみてしっかりパファーマンスが改善されているか判断してコーディングしましょう
##まとめ
N+1問題を作るようなコード書くとブヒブヒ言われそうなので、意識して書かないようにしましょう。
RDMについてはこのカレンダー中に記事にできそうかわからないけど絶対記事にする。
参考先にbulletとかいう便利なgemのこと書いてあったからそれもいつか書かなきゃですな。
##参考にしたの
【Rails入門】パフォーマンスが悪いならincludes/orderを検討しよう
https://www.sejuku.net/blog/26168
Railsライブラリ紹介: N+1問題を検出する「bullet」
http://www.techscore.com/blog/2012/12/25/rails%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E7%B4%B9%E4%BB%8B-n1%E5%95%8F%E9%A1%8C%E3%82%92%E6%A4%9C%E5%87%BA%E3%81%99%E3%82%8B%E3%80%8Cbullet%E3%80%8D/