サイトを運営していると、レスポンスを早くするにはどうすればいいかと常に考えますね。
サーバーの性能を上げたり、ネットワーク環境を良くしたりとハードウエアでの対応も重要ですが、実際に動いているコードの最適化が一番大切な所ですね。
123ishはRailsで出来ていますが、コードの最適化にBullet というジャムを使っています。
Rails の便利なオブジェクト関連性の定義によって、実は一つで済むようなSQL呼び出しが、関連するレコードをSQLから一つ一つ呼び出すという、とても時間のかかる実装に陥ってしまうことがあります。
一括読読み込みをすれば2回ですむSQL呼び出しが、そうでないと11回もSQL呼び出しをすることになってしまうという簡単な例と共に、このN+1クエリ問題についてRailsガイドに詳しく載っています。
このN+1クエリ問題を見つけてくれる便利なジャムがBullet です。
また、何時でも一括読み込みをすれば良いのでもなく、むしろ要らない読み込みはメモリーの浪費と逆にレスポンスを遅くしてしまいます。
- N+1クエリ問題の発見
- 無駄な一括読み込みの発見
が出来るのです。
Bulletジャムの導入方法
- BulletジャムをGemfile に記述
- 新しい環境ファイル optimization.rbの設定
- ジャムをoptimizationの時にのみ取り込み
- 実行
1. BulletジャムをGemfile に記述
2020年7月現在でバージョンは6.1.0でした。
2. 新し環境設定
Bulletを実行する環境を、optimizationとして普段使っているdevelopmentから分けます。development.rbをコピーしてobpimization.rbとしてconfig/environments に作り、以下のような設定を施します。
- Bullet.enable = tureはBulletジャムを使って最適化を行うことを可能にします。
- Bullet.alert = tureは問題点をjavascript のalertを使って表示することを可能とします。
- Bullet.bullet_logger = trueはログをファイルにとっていくことを可能にします。ログはRails.root/log/bullet.logでとられます。
- Bullet.console = trueはブラウザーのjavascript consoleにN+1問題を表示することを可能とします。
- Bullet.rails_logger = trueはBulletジャムがRailsのログに記録することを可能とします。
- Bullet.add_footer = trueは問題点をフッターに表示することを可能にします。
他の設定はBulletのオフィシャルサイトを参照にしてください。
おっと、webpacker.ymlにoptimizaionの環境を追加するのも忘れないでください。
3.optimization環境でBulletジャムを使います
Bulletジャムはoptimization環境で使います。
4.optimization環境でRailsを実行
実行する時にoptimization環境を読みます(デフォルトでは開発環境が使われますね)。
bundle exec rails server -e optimization
チェックするページに行くと、問題点があれば以下のイメージにあるように指摘してくれます。Bullet.alertとBullet.add_footerを2つともtrueにしているので、両方に表示されています
Bulletのメッセージの例
終わりに
N+1クエリも余分な一括読み込みも、どちらもレスポンスを非常に遅くしてしまいます。これを発見してくれるBulletジャムは、Railsのコードレベルでの最適化の強力な助っ人です。
よく注意しないと、N+1コードはいつの間にか入り込んでしまうし、更に余分な読み込みを書いてしまったりすることは頻繁にあることです。
でもBulletは、これらの問題を発見しコードの最適化を効率的に行うことを可能にしてくれます。
でも、Bulletがしてくれるのは問題点の発見であって、問題自体は解決はしてくれません!実際にコードの最適化をするのは開発者です。
123ishでは定期的にoptimizaion環境を使ってチェックを行っています。でも、立ち上がりが遅いので、普段は軽いdevelopment環境で開発しています。