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