経緯
N+1問題が発生しないようにプログラムを書いているはずだけど、どこかで起きてしまっていそうで不安。。。
ということがあって、何か判定してくれるGemないかなーと思ってたら、案の定あったので、ご紹介。
N+1問題とは
そもそもN+1問題って何?って人のために。
例えば、Articleに紐づくUserというものがあったとします。Article一覧を出しつつ、著者の名前も表示したいというとき、単純にかくと、以下のようになります。
class ArticlesController < ApplicationController def index @articles = Article.all end end
<table> <thead> <tr> <th>タイトル</th> <th>コメント数</th> </tr> </thead> <tbody> <% @articles.each do |article| %> <tr> <td><%= article.title %></td> <td><%= article.user.name %></td> </tr> <% end %> </tbody> </table>
ただ、ここでログを見ていると、
SELECT "articles"* FROM "articles";
のあとに
SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
みたいなものが大量に吐かれます。
最初、記事一件を取得するために1クエリが走って、そのあと、N件あれば、Nクエリ走ってしまうことから「N+1問題」と呼ばれています。
これを放置しておくと、100万件とかになったとき、パフォーマンスに影響してしまいます。
Bullet
https://github.com/flyerhzm/bullet
いつものようにGemfileの中にgem 'bullet', group: :development
と書いて、bundle install --path vendor/bundle
を実行してやりましょう。
config.after_initialize do Bullet.enable = true Bullet.alert = true Bullet.bullet_logger = true Bullet.console = true Bullet.rails_logger = true end
あとは、普通にWebサーバーを起動するだけ。http://example.com/articles/
にアクセスすると、「N+1問題が発生してるよ!」とJSのアラートが表示されます。
まとめ
パフォーマンスに運用上、影響しないところでも、パッとできることで、修正できるなら、直しておいてあげたほうがプロダクトとしては健全ですよね。
コメントを残す