概要
原著者の許諾を得て翻訳・公開いたします。
Rails tips: 遅いクエリのログをDB設定変更なしで取るコツ(翻訳)
アプリの種類を問わず、遅いクエリのログを読むのはパフォーマンス向上のためのリファクタリングで弱い部分を発見するよい方法のひとつです。
以前の私は、遅いクエリのログというとデータベースエンジンで生成されたログのことが念頭にありました。しかし、データベースの遅いクエリのログを取る独自のメカニズムを作れることをご存知でしょうか?RailsのActiveSupport::Notifications
モジュールを使うと、指定のイベントをサブスクライブできます。イベントのひとつに sql.active_record
があり、これはデータベース操作のたびにトリガされます。
次のような感じで使えます。
ActiveSupport::Notifications.subscribe('sql.active_record') do |name, start, finish, id, payload|
# interesting stuff
end
以下の興味深い変数があります。
- payload: クエリの詳細を含むハッシュで、
payload[:sql]
でクエリを取得できます - start: クエリ開始時の
Time
オブジェクトです - finish: クエリ終了時の
Time
オブジェクトです
次の方法で、クエリに要した時間を簡単に取得できます。
ActiveSupport::Notifications.subscribe('sql.active_record') do |name, start, finish, id, payload|
duration = finish.to_f - start.to_f
end
3秒後に遅いクエリが開始するのであれば、次のようにしてクエリのログを取れます。
ActiveSupport::Notifications.subscribe('sql.active_record') do |name, start, finish, id, payload|
duration = finish.to_f - start.to_f
if duration >= 3.0
SomeLogger.log("slow query detected: #{payload[:sql]}, duration: #{duration}")
end
end
Railsアプリ用のイニシャライザを作成する
遅いクエリロガーの基本的な機能ができたので、実際にrailsプロジェクトに放り込んでサーバーで動かしてみましょう。SlowQueryLogger
クラスを作成し、config/initializer/slow_query_logger.rb
に保存します。
class SlowQueryLogger
MAX_DURATION = 3.0
def self.initialize!
ActiveSupport::Notifications.subscribe('sql.active_record') do |name, start, finish, id, payload|
duration = finish.to_f - start.to_f
if duration >= MAX_DURATION
SomeLogger.log("slow query detected: #{payload[:sql]}, duration: #{duration}")
end
end
end
end
SlowQueryLogger.initialize!
これで、遅いクエリのログが出力されます。このクラスはどのプロジェクトでも使える手頃な作りで、何となればgem化してクエリパフォーマンスを改善したい箇所の特定に役立てることもできます。警告をファイルに出力する代わりに、Rollbarなどの監視システムに送ることもできます。
お知らせ: RSpec & TDDの電子書籍を無料でダウンロード
もっと稼ぎたい方や会社をさらに発展させたい方へ: テスティングのスキルの重要性にお気づきでしょうか?テストを正しく書き始めることが、唯一のファーストステップです。無料でダウンロードいただける私の書籍『RSpec & Test Driven Developmentの無料ebook』をどうぞお役立てください。