Tech Racho エンジニアの「?」を「!」に。
  • 開発

Rails tips: 遅いクエリのログをDB設定変更なしで取るコツ(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

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』をどうぞお役立てください。

関連記事

[Rails5] Active Supportの概要をつかむ

[Ruby] module_functionでモジュールの特異メソッドを簡潔に書く


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。