LoginSignup
1
0

More than 1 year has passed since last update.

gem bullet による警告が消えても必ずログを確認する必要がある

Last updated at Posted at 2022-02-19

初学者向けに書きました。
これはまだ自分が初学者だった頃のメモです。もはや何番煎じかわからない内容ですが、何か記事を書きたかったので書きました。
間違い等ありましたら申し訳ございません。ボコボコにコメントしてやってください。すぐ直します。

伝えたいこと

  • bulletを使用していても検知されないN+1問題がある。
    • bulletによる警告が出ていないからといって満足して終わらないように。ちゃんとチェックしよう。
  • N+1問題が解決していても本当にそれが最適な処理になっているのか吟味しよう。

bullet とは

  • N+1問題を検知するgemです。詳しくは公式で。

問題①:検知できないN+1問題

例えば、以下のコードはN+1問題を発生させますが、この問題はbulletでは検知できません。

class Post < ApplicationRecord
  has_many :comments
end

@posts = Post.preload(:comments).all

@posts.each do |post|
  post.comments.count
end

これはcomments自体はキャッシュしているので、post.commentsとした時にSQLが実行されることはありません。
しかし、このcountメソッド(ActiveRecord::Associations::CollectionProxy)は、実行の度にSQLを必ず実行するためN+1問題が発生します。仕様はここ

このcountメソッドような、モデルのアソシエーションの自動ロードの仕様に関わらず、そのメソッド自身の仕様によるクエリによって発生するN+1問題はbulletでは検知できません。ActiveRecord::FinderMethodsのfindメソッド等を使用した場合でも同様の問題が発生します。

なので、bulletの警告が無くなったとしてもちゃんとログを確認するようにしましょう。

問題②:アソシエーションの「キャッシュの方法」については言及しない

例えば、以下のコードの時、N+1問題は発生せず問題無いように見えます。

class Post < ApplicationRecord
  belongs_to :user
end

@posts = Post.preload(:user).all

@posts.each do |post|
  p post.user
end

ところがこれは、完璧ではありません。
基本的にこのような場合は、preloadではなくeager_loadをすべきです。例外は除きます。
この例のような処理だけではどっちでキャッシュしても大差ないですが、大規模なデータを処理する場合は処理に係るコストがまったく異なります。
詳しい説明はこの記事の本旨と異なるので行いませんが、簡単に言うと以下の2点です。

  • 外部結合と内部結合の違い
  • 実行クエリ数の違い

こういった問題はbulletでは警告を受けません。あくまでeager loadingに対して警告をするだけです。
警告内容は、`includes@メソッドを使用するかしないかで抽象的に指摘しているに過ぎません。

なので、eager_loadpreloadの仕様を理解することを初めに、ログの実行時間や全体の処理内容を考慮しつつ最適化を行うよう気をつけてください。bulletによる警告が無くなったからといって油断しては行けません。

まとめ

  • bulletを使用していても検知されないN+1問題がある。
    • モデルのアソシエーションの自動ロードの仕様に関わらず、そのメソッド自身の仕様によるクエリによって発生するN+1問題はbulletでは検知できない。
    • eager loadingの方法については言及されない。
  • ActiveRecordに係るメソッドの仕様は正確に捉えられるようにしよう。
1
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
1
0