THINKING MEGANE

MySQLのslow_logテーブルをサマライズするGemをつくった

MySQLにはログファイルに出力したスロークエリをサマライズするmysqldumpslowコマンドがあって重宝していたのですが、出力先をテーブルに変更すると使えなくなってしまったので、同じことができるmysql_dump_slowというGemをつくりました。

使い方

ActiveRecordで取得したスローログを渡して使います。

# ActiveRecordでmysql.slow_logテーブルのレコードを取得します
logs = SlowLog.all

# スローログをサマライズします
summary = MysqlDumpSlow.summarize(logs)
summary.each do |counter|
  # mysqldumpslowコマンド形式で出力することができます
  counter.to_mysqldumpslow
  # => Count: 2  Time=100s (200s)  Lock=200s (400s)  Rows=300 (600),  2hosts
  #      SELECT * FROM T
end

to_mysqldumpを使って、サマリした結果ごとにmysqldumpslowコマンドの形式で出力することができます。

社内ではこんな感じで前日分のスロークエリをSlackに通知するrakeタスクに組み込んで使っています。

mysql\_dump\_slow

このように某清貧会会長に煽られるので緊張感もってスロークエリの撲滅に取り組んでいます。

getter

自分で結果を整形して使いたい場合は、それぞれの total, average の値を取得できます。

counter.total_query_time   # => 100000
counter.average_query_time # => 100000

以下の値を取得可能です。

  • total_count
  • [ total | average ]_query_time
  • [ total | average ]_lock_time
  • [ total | average ]_rows_set
  • user_hosts

サマリについて

mysqldumpslowと同じ方式でサマライズします。

具体的には、同じクエリに対してそれぞれの実行時間、ロック時間、取得行数を集計し、合計、平均を求めます。

また、クエリについてはパラメタを抽象化しており、条件の値が違うだけのクエリであれば同じクエリと見なします。

SELECT * FROM `users` WHERE `users`.`name` = 'hoge' AND `users`.`age` > 20
SELECT * FROM `users` WHERE `users`.`name` = 'fuga' AND `users`.`age` > 30

のようなクエリは

SELECT * FROM `users` WHERE `users`.`name` = 'S' AND `users`.`age` > N

のように抽象化され、同じクエリと見なします。

インストール

RubyGemsに公開しているのでGemfileに書いてbundle installすればOKです。

gem 'mysql_dump_slow'

まとめ

ログファイルの場合、解析するためにファイルを取得する必要があって少し手間がかかっていたのが、テーブルに出力することでクエリで取得できるようになって取り扱いしやすくなりました。

実装にあたっては同僚の@mizoRにいろいろアドバイスもらえて助かりました。Thanks!

スロークエリが常に通知される状態になったことで、どんどん撲滅していくぞという空気が生まれるんじゃないかなと思ってます。よければ使ってみてください。

このエントリーをはてなブックマークに追加