LoginSignup
4
10

More than 5 years have passed since last update.

RailsのN+1問題の解決方法 初心者→中級者へのSTEP9/25

Last updated at Posted at 2018-12-09

RailsのN+1問題の解決方法

はじめに
RDM楽しかったです。後々、記事にしてみせます。二日酔いです。頑張って書きます。
今回はパフォーマンスを悪くするN+1問題の解決方法についてです。

N+1問題とは

コードをみた方が早いかもしれません。下記コードをみてください。

user.rb
class User < ApplicationRecord
  has_one :blog
end
blog.rb
class Blog < ApplicationRecord
  belongs_to :user, foreign_key: "user_id"
end

わかりすいようにユーザーがブログを一つ持つようなリレーションモデルを考えます。
user#indesにて各ユーザーの名前とそのユーザーのブログ名を表示するようにします。

view/user/index.html.haml
- @users.each do |user|
  = user.name
  = user.blog.name

このコードによるクエリは以下のようになります。
スクリーンショット 2018-12-09 23.33.59.png

各ユーザーごとにBlogテーブルにアクセスしています。これがもしユーザー数が千、万、10万...となってくると非常にパファーマンスが悪いです。これがN+1問題です。(user一覧表示の為のデータ取得のSELECTが1、各ユーザのブログを取得する為のSELECTがNとなります)

パフォーマンス向上の為、ブログテーブルへのSELECTを一回にしたいです。

解決方法のincludes

解決策は簡単で、includesを使うだけです、includesメソッドは関連するテーブルをまとめて取得してくれます。

view/user/index.html.haml
- @user_index.includes(:blog).each do |user|
  = user.blog.name

スクリーンショット 2018-12-09 23.42.01.png

これでブログテーブルへの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/

4
10
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
4
10