QA@IT

RailsでのSQLのN+1問題の解決法

5800 PV

現在、Rails3.2を使ってシステムを開発しているのですが、SQLのN+1問題をどのように解決すればいいか判断がつかず困っています。

具体的にこのQA@IT例を挙げて説明させていただきます。

このサービスはTopページに「質問(以後Question)」の一覧と、その質問に関連する「タグ(以後Tag)」の一覧を表示しています。

私はこのような処理をするを実現する時に、こう書きました。
なおquestionとtagは、多対多関連をむすんでいるものとします。

Controller

@questions = Questions.all

View

<% questions.each do |question| %>
  <%= question.name %>
  <% question.tags.each do |tag| %>
       <%= tag.name %>
  <% end %>
<% end %>

このViewを表示すると、
Tag.findが@questions.count分流れてしまいます(N+1問題)。

この問題を解決する手段として、
あらかじめ必要になるTagsをquestionをキーとしたHash形式で、あらかじめもっておくべきかと現在は考えているのですが、少し強引な感じ(独自のアルゴリズムを使っているので)して、なにかもっとスマートな方法があるのではないかと考えています。

そこでこの問題を解決する際にもっとスマートな方法、ないしはこの方法がベスト。というご指摘をいただきたいのです。

よろしくお願いします。

回答

findのincludeオプションを利用して以下の様にしてはどうでしょうか。

@questions = Qustion.all(:include => :tag)

また、N+1を検出してくれるbulletというgemもあるようです。
実行時に負荷はかかるようですが、自動的というのは魅力です。
https://github.com/flyerhzm/bullet

編集 履歴 (1)
  • なるほど、includeを使えば先に関連先を読み込んで、forでもSQLが発行されないんですね。おかげさまで解決できました、ありがとうございます。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。