🚀
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問題を検出し、アラートを表示してくれます。
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