なんかかきたい

プログラミングなどの個人的なメモやサークル「ゆきいろパラソル」の情報を載せてます

MySQLで定期的に SHOW PROCESSLIST を実行して長時間走っているクエリを探す

前略、大きいMySQLのデータベースがあります。すると、大きなデータベースから多くのデータを取得するため、非常に重いクエリが実行されることがあります。 そうするとデータベースが高負荷になるため重い処理を見つけたくなります。 (innodb_query_queued とかが増えて辛くなる)

MySQLには SHOW PROCESSLIST というものがあり、実行中のMySQLのプロセス一覧を見ることができ、 クエリの実行状況や実行時間をみることができるのでスロークエリログより便利なことがあります。 (スロークエリログはクエリが完了した場合に出力されるため実行中やクエリを中断した場合に見ることができない)

しかし、SHOW PROCESSLIST の出力は多いため毎回見るのは疲れます。そこで以下のようなスクリプトSHOW FULL PROCESSLIST の出力をフィルターすると便利です。

require 'mysql2'

MYSQL_USER = ''
MYSQL_PASS = ''
LONG_QUERY_THRESHOLD = 60

client = Mysql2::Client.new(host: 'localhost', username: MYSQL_USER, password: MYSQL_PASS)
client.query('SHOW FULL PROCESSLIST').each do |row|
  next unless row["Command"] == "Query"
  next if row["Time"] < LONG_QUERY_THRESHOLD

  puts ([Time.now] + row.values.map { |v| v.to_s&.gsub("\n", " ") }).join("\t")
end

実行コマンドがQueryかつ実行時間の閾値を超えた場合にのみ出力します。 複数回の出力をフィルターしないので、時間がかかっているクエリはなんども見ることになります。クエリに長い文字列が来ることもあるので、 実運用のことを考えるとある程度の長さで切った方がいいかもですね。