【Rails】N+1問題

Ruby on Railsアイキャッチ画像

N+1問題
このネーミングから、+1が何か悪さしているんだろうな。
そう思いませんでしたか?僕はそう思いました。はい全然違いました。
あと、何が起きているのかなかなか理解出来なかったのでまとめておきます。

1よりもNの方が問題!
この問題に名前をつけるとしたら、「クエリ発行数問題」こっちの方がしっくりくる。

要は、クエリ発行数を減らすために、
allで全件取得するのをやめて、
selectでカラムを絞るか、
アソシエーションとincludeメソッドを使って絞る
というもの。

<% @blogs.each do |blog| %>
  <%= blog.user.name %>
<% end %>

このuserは、
アソシエーションメソッド(つまり、belongs_to :user)で定義したuser

コントローラ
❌@blogs = Blog.allの時

blogの数だけ、usersテーブルからnameを探す。
blogの個数分(N個)のクエリが発行される。

発行されるSQL
①blogsテーブルにアクセス これが1回
②blogsテーブルにあるレコードの数だけアクセス これがN回

クエリ発行数を減らすincludeメソッドを使うと
コントローラ
⭕@blogs = Blog.all.includes(:user)

userが紐付いているblogのuserのnameだけ探す。
blogsテーブルとusersテーブルのレコードを関連させてblogデータを一発で取得できる。

発行されるSQL
①usersテーブルの全てのレコードを取得
②blogsテーブルからWHERE句で指定した条件にマッチするレコードを取得
blogsテーブルへのアクセスは1回

特定のフィールドだけを取り出すselectメソッド
@blogs = Blog.select(:id, :titile, :content, :created_at)

この問題の本質を付いている名前はN+1のような気もしてきました。

参考
https://pikawaka.com/rails/includes

コメント