🚀

RailsにおけるN+1問題とは

に公開

N+1問題とは

以下のようなビューを見てください。このときcontrollerでは、current_userのpostを検索するSQLクエリが実行されます。また、viewでは、userのpostsをループで回しcommentのidを表示しています。このとき、ループの中で毎回postに紐づくコメントを検索するSQLクエリが実行されます。例えばcurrent_userが持つ、postが10件の場合、各postに紐づくコメントを検索するために10個のSQLが実行されてしまいます。この問題をN+1問題といいます。

// controller
@posts = current_user.posts

// view
<% @posts.each do |post| %>p
    <%= post.comment.id %>
<% end %>

N+1問題の解決策

N+1問題を解決するにはviewでループを回す前に、commentをincludeしてあげることで一回のクエリで各postのコメントが取得できます。

// controller
@posts = current_user.posts.includes(:comment)

// view
<% @posts.each do |post| %>p
    <%= post.comment.id %>
<% end %>

bullet(ブレット)

bulletというGemがN+1問題を検出し、アラートを表示してくれます。
https://github.com/flyerhzm/bullet

bulletを使っていてつまづいたところ

こちらの例でcurrent_userが保持しているpostが一つの場合、N+1問題は発生しません。よってincludes(:comment)をしていなくても、bulletによるアラートが表示されません。
しかし、postを複数保持している場合はN+1問題が発生するので、includes(:comment)する必要があります。
よって、postの数によってbulletがN+1問題を検出してくれたり、してくれなかったりします。
結論として、postを複数持てる場合はincludes(:comment)はしたほうがいいと考えました。

// controller
@posts = current_user.posts

// view
<% @posts.each do |post| %>p
    <%= post.comment.id %>
<% end %>

Discussion