0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

N+1問題の検出・対策(bullet gemを使用する)

Last updated at Posted at 2023-03-07

N+1問題とは

一覧ページの表示等で、1件表示に対して1つのクエリを発行してしまう事をN+1問題という。
N+1が起きるとDBとの通信回数が多くなりレスポンスが遅くなるのでパフォーマンスが落ちる。
特にRailsのActiveRecordなどのORMを使っている初学者は、生身のクエリを意識せずに実装できてしまうため、この問題に気付きにくいと思う。

どうやって見つける?

N+1の発生箇所を検出してくれるbulletという便利なgemがある。
bulletは、N+1を検出するとウインドウ表示してくれるので書かれている対象を修正していけば良い。

導入方法

bulletのインストール

development環境に入れるので developmentグループに以下を追加します

test-app/Gemfile
gem 'bullet'

bulletのconfig設定

config/environments/development.rb
  # Bullet gem config
  test-app::Application.configure do
    config.after_initialize do
      Bullet.enable = true # Bulletプラグインを有効
      Bullet.alert = true # JavaScriptでの通知
      Bullet.bullet_logger = true # log/bullet.logへの出力
      Bullet.console = true # ブラウザのコンソールログに記録
      Bullet.rails_logger = true # Railsログに出力
    end
  end

bulletを使う

N+1の検出

develop環境でrails serverを起動し、特に動作の遅いページを表示する。
bulletがN+1を自動検出してくれるのでウインドウ表示を確認する。

N+1の対策

ActiveRecordのクエリにincludesを記述する。
(includesで無駄なクエリを一つに束ねることができる)

例)ransackに発生していたN+1(修正後)
  def set_ransack
    @q = User.sort_by_name.ransack(params[:q])
    @users = @q.result(distinct: true).page(params[:page]).includes(image_attachment:[:blob])
  end

クエリのパフォーマンス測定

N+1の改善後、どの程度パフォーマンスに変化があるか測定しよう。
(改善前・改善後で実行値を比較する)

EXPLAINコマンドで、N+1が発生していたクエリの実行計画を測定する
$ EXPLAIN SELECT * FROM item;

                       QUERY PLAN
---------------------------------------------------------
Seq Scan on item (cost=0.00..12.20 rows=220 width=328)
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?