Rubyが好きなプログラマーの日記。日々の生活、開発に関するメモとか考えとか。
パフォーマンスに影響するN+1問題を解決するために、bullet を入れて、問題が起きている箇所を検出しつつ修正してみたんだけど、逆に悪くなったりしていた。
Rails のログを見ながら試してみたところ、Eager Loadする includes を差し込むと、その時点での対象を全てロードするということが原因だということがわかった。
例えば、
class Post < ActiveRecord::Base
scope :published, -> { where(public: true) }
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :post
end
のようなモデルがあった時に、
Post.includes(:comments).publishedPost.published.includes(:comments)とでは結果は同じであるが、両者ともにN+1問題を解決しているものの、前者の方がパフォーマンスが悪い。これは、Post.includes(:comments) とした時点でEager Loadingが実施されるため、この時点だと、Post.all に関連するComment をロードし、その後にpublished スコープでPostを絞り込んでいる。余計なCommentレコードまでロードしているため、パフォーマンスが良くない(もしくは悪くなる)ようだ。
なので、そういったことを回避するために、後者のようにscopeやwhereで絞り込んでからincludes でロードすると良い。