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でモジュールの特異メソッドを簡潔に書く

Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好き。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ