- 更新日: 2016年1月18日
- Rails
RailsのN+1問題をBulletで検出する
Rails で N+1問題を検出するには gem の bullet を使うと便利です。bullet は、N+1問題の検出以外にも、不要な使われていない Eager Loading の検出なども行ってくれます。
Bullet をインストールして使うと、N+1 問題や不要な Eager Loading を発見しやすくなります。
— 環境 —
Rails 4.1.1
Ruby 2.1.2
N + 1 問題とは
N+1 問題は、has_many アソシエーション関係のあるコレクションを、テンプレートでループして出力させる場合などに起こりやすい。
本来 ActiveRecord でいう includes(SQL の JOIN)等を正しく使えば1〜2回で済む SQL クエリ発行が、N+1 回の SQL クエリを発行してしまう問題です。私も時々ミスってやってしまいます…。
また、ActiveRecord などデータベースへのアクセスを抽象化する OR マッパーのライブラリを使っている場合に、N + 1 問題が発生しやすい。OR マッパーは便利とはいえ、効率の良い SQL クエリを実行するには、OR マッパーの命令がどんな SQL 文を発行するのか知っておく必要がありますね。
もっと詳しく N+1 問題や Eager Loading について知りたい場合は、以下のページが分かりやすいです。
N+1問題 / Eager Loading とは – Rails Webook
Bullet インストール
では、本題へ。Bullet のインストール手順です。gem なので簡単。Gemfile に bullet を追記して、bundler でインストールします。
Gemfile
1 2 3 4 |
group :development do # ... gem 'bullet' end |
インストール。
1 2 3 |
$ bundle install |
Bullet の設定
Bullet をインストールし終わったら、config/environments/development.rb に設定を行う。
config/environments/development.rb
1 2 3 4 5 6 7 8 9 10 11 |
AppName::Application.configure do # ... # bullet settings config.after_initialize do Bullet.enable = true Bullet.bullet_logger = true Bullet.console = true Bullet.add_footer = true end end |
各々の設定の意味は、README によると以下のとおりです。
Bullet.enable: enable Bullet gem, otherwise do nothing
Bullet を有効にする、これを true にしないと Bullet を何もしない。
Bullet.bullet_logger: log to the Bullet log file (Rails.root/log/bullet.log)
Rails.root/log/bullet.log にログを記録する。
Bullet.console: log warnings to your browser’s console.log (Safari/Webkit browsers or Firefox w/Firebug installed)
ブラウザのコンソールに warnings のログを出力する。
Bullet.add_footer: adds the details in the bottom left corner of the page
ページのフッター左に詳細を表示する。
その他にも設定項目が多数用意されています。Slack や Airbrake などに通知する設定もできるので、他の設定項目についての詳細は README を参考。
Bullet を使ってN+1問題を修正
例として User has_many Brushups というアソシエーションの関係のモデルがあったとして、以下のようなコードを書くと N + 1 問題が発生してしまいます。
app/controllers/home_controller.rb
1 2 3 4 5 |
class HomeController < ApplicationController def index @brushups = Brushup.all end end |
app/views/home/index.html.erb
1 2 3 |
<% @brushups.each do |brushup| %> <%= brushup.user.name %> <% end %> |
このアクションの URL にアクセスしたところ、ページのフッター部に “N+1 Query detected” の警告が表示されました。
Bullet がN+1問題を検出してくれましたので、コントローラーのコードを以下のように includes を使って修正します。
app/controllers/home_controller.rb
1 2 3 4 5 |
class HomeController < ApplicationController def index @brushups = Brushup.all.includes(:user) end end |
これで Bullet によるフッター部の警告表示が消えまして、N + 1 問題を解消できました。Bullet 便利です。
- – 参考リンク –
- Railsでbulletを使ってN+1問題を発見しDBアクセスのパフォーマンスを向上させる – Rails Webook
- ?? Railsライブラリ紹介: N+1問題を検出する「bullet」 TECHSCORE BLOG
- Rails – ActiveRecordのjoinsとpreloadとincludesとeager_loadの違い – Qiita
- Rails – INNER JOIN で eager loading – Qiita
- Ruby – joinsを使ってeager loadingをする方法 – Qiita
- Rails の関連記事
- RailsでMySQLパーティショニングのマイグレーション
- Rails ActiveRecordでdatetime型カラムのGROUP BY集計にタイムゾーンを考慮する
- RailsプラグインGemの作成方法、RSpecテストまで含めたrails pluginの作り方
- RailsでAMPに対応するgemをリリースしました
- Railsでrequest.urlとrequest.original_urlの違い
- Railsでwheneverによるcronバッチ処理
- Google AnalyticsのRails Turbolinks対応
- Railsアプリにソーシャル・シェアボタンを簡単設置
- Rails監視ツール用にErrbitをHerokuで運用
- Facebook APIバージョンのアップグレード手順(Rails OmniAuth)
- 初回公開日: 2016年1月14日
Leave Your Message!