データベース

スロークエリログとは|MySQLの設定・見方・解析ツールと改善手順

スロークエリログとは、設定した実行時間(しきい値)を超えて遅かったSQLを記録するMySQLのログ機能です。どのクエリが、どれくらいの時間、どれだけの行を読んで遅くなっているのかが残るため、データベースのボトルネックを特定する最初の手がかりになります。混同しやすい「スロークエリ」は遅いクエリそのものを指す言葉で、その遅いクエリを記録する仕組みが「スロークエリログ」です。

この記事では、スロークエリログの定義とスロークエリとの違いから、一般クエリログ・バイナリログとの役割の違い、slow_query_loglong_query_time での設定方法、出力項目(Query_time・Rows_examined など)の読み方、mysqldumpslow・pt-query-digest での解析、検出した遅いクエリをEXPLAINとインデックスで改善する手順、MySQL 8.0以降・MariaDBでの違い、ログローテーションまでを順に解説します。

まとめ:スロークエリログの要点

先に結論を整理します。スロークエリログは long_query_time(デフォルト10秒)を超えたSQLを記録する機能で、デフォルトでは無効です。MySQLでは SET GLOBAL slow_query_log = 'ON'; で即時に、my.cnf への記述で恒久的に有効化できます。ログには遅かったSQLと実行時間(Query_time)・ロック待ち(Lock_time)・送信行数(Rows_sent)・検査行数(Rows_examined)が残り、Rows_examined が Rows_sent に対して極端に大きいクエリがインデックス改善の最有力候補です。大量のログは mysqldumpslow(MySQL同梱)や pt-query-digest(Percona Toolkit)で集計し、遅いクエリ上位から EXPLAIN とインデックスで対処します。本番では long_query_time を1秒前後まで下げて運用するのが実務的な出発点です。以降で各手順を具体的に見ていきます。

スロークエリログとは|スロークエリとの違い

スロークエリログとは、MySQLが「遅い」と判定したSQLを記録するログです。何秒以上を遅いとみなすかは long_query_time で決め、この値を超えた実行時間のクエリがログファイルに追記されます。記録されるのは遅かったSQL文だけでなく、実行時刻・実行時間・ロック待ち時間・送受信した行数といった、原因分析に必要な周辺情報も含みます。

検索でよく並ぶ「スロークエリ」と「スロークエリログ」は別物です。スロークエリは実行に時間のかかる遅いクエリそのもの、スロークエリログはその遅いクエリを集めて残す記録です。つまり「スロークエリを見つけるためにスロークエリログを使う」という関係になります。アプリの応答が遅い、特定の時間帯だけ重い、といった症状の原因をデータベース側から切り分けるときに、まず確認するのがこのログです。

一般クエリログ・バイナリログとの違い

MySQLには似た名前のログが複数あり、「mysql クエリログ」を探すと役割を取り違えやすいので整理します。スロークエリログは遅いクエリだけを記録する性能調査用、一般クエリログ(general query log)は接続から実行まですべてのSQLを記録するデバッグ・監査用、バイナリログ(binary log)はデータ変更(INSERT/UPDATE/DELETE 等)をレプリケーションとリカバリのために記録するものです。目的が異なるため、性能改善の調査で見るべきはスロークエリログです。

ログ種別 記録対象 主な用途 既定
スロークエリログ しきい値超の遅いSQL 性能改善・ボトルネック特定 無効
一般クエリログ すべてのSQL・接続 デバッグ・監査 無効
バイナリログ データ変更の記録 レプリケーション・復旧 8.0で既定有効

一般クエリログは全クエリを書き出すため本番では負荷とログ量が大きく、常時有効には向きません。日常の性能監視はスロークエリログ、不具合の再現調査だけ一時的に一般クエリログ、という使い分けが基本です。

MySQLでスロークエリログを有効にする設定方法

有効化には、再起動なしで効く一時設定と、my.cnf に書く恒久設定の2通りがあります。検証中はSET GLOBAL、本番運用では設定ファイルに残すのが定石です。

一時的に有効化する(SET GLOBAL・再起動不要)

稼働中のサーバーで今すぐ試すなら、グローバル変数を変更します。long_query_time の変更は以降の新規接続から反映される点に注意してください。

-- 即時に有効化(再起動不要、新規接続から反映)
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';

-- 現在の設定を確認
SHOW VARIABLES LIKE 'slow_query%';
SHOW VARIABLES LIKE 'long_query_time';

恒久的に有効化する(my.cnf)

サーバー再起動後も維持したい場合は設定ファイルに記述します。Linuxでは /etc/my.cnf または /etc/mysql/my.cnf[mysqld] セクションに追記し、MySQLを再起動します。

[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
log_queries_not_using_indexes = 1
min_examined_row_limit = 100

主要パラメータの意味

設定値はやみくもに付けると逆効果です。とくに log_queries_not_using_indexes は無索引クエリをすべて記録するため、件数が膨れて本当に直すべきクエリが埋もれやすくなります。

パラメータ 意味 既定
slow_query_log スロークエリログの有効/無効 無効(0)
long_query_time 遅いと判定する秒数(μs精度) 10
slow_query_log_file 出力先ファイルパス host_name-slow.log
log_queries_not_using_indexes 無索引クエリも記録 無効
min_examined_row_limit 検査行数の下限で記録対象を絞る 0

スロークエリログの見方|出力項目の読み方

ログには1クエリごとに、コメント行(# で始まる統計)と実際のSQLが残ります。次は1秒を超えたSELECTが記録された例です。

# Time: 2026-06-28T10:00:00.123456Z
# User@Host: app[app] @ localhost []
# Query_time: 5.234567  Lock_time: 0.000123  Rows_sent: 12  Rows_examined: 1840000
SET timestamp=1782990000;
SELECT * FROM orders WHERE customer_id = 42;

読みどころは4つの数値です。Query_time は実行にかかった秒数、Lock_time はロック待ちの秒数、Rows_sent はクライアントに返した行数、Rows_examined はMySQLが内部で走査した行数です。とくに重要なのが Rows_sent と Rows_examined の差で、上の例は12行を返すために184万行を走査しており、インデックスが効かずフルスキャンしている典型です。Lock_time が大きい場合はロック競合、Query_time だけ大きく行数が少ない場合は関数や一時テーブル・ソートを疑います。

スロークエリログの解析ツール|mysqldumpslow と pt-query-digest

ログが数百〜数千件になると目視は非効率です。同じSQLパターンを集計し、合計時間や出現回数の多い順に並べてくれる解析ツールを使います。

手軽なのはMySQLに同梱される mysqldumpslow です。次のコマンドは合計実行時間の長いクエリを上位10件表示します。

# 合計実行時間が長い順に上位10件(-s t = 時間, -t 10 = 上位10)
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log

より詳細に分析するなら Percona Toolkit の pt-query-digest が定番です。クエリごとの実行回数・合計/平均時間・Rows_examined の分布まで集計でき、改善優先度を判断しやすくなります。

pt-query-digest /var/log/mysql/slow.log

使い分けの目安は、まず mysqldumpslow で当たりを付け、継続的なチューニングや大量ログの精査では pt-query-digest を使う、という流れです。

検出した遅いクエリを改善する手順

遅いクエリを見つけたら、EXPLAINで実行計画を確認します。type が ALL(フルスキャン)になっていないか、key(使用インデックス)がNULLでないか、rows(推定走査行数)が大きすぎないかを見ます。

EXPLAIN SELECT * FROM orders WHERE customer_id = 42;

WHERE・JOIN・ORDER BY で頻繁に使う列にインデックスが無ければ、追加で走査行数を大きく減らせます。SELECT * をやめて必要な列だけ取得する、関数を列側にかけてインデックスを無効化していないか見直す、といった点も効果的です。改善後は同じクエリを再実行し、スロークエリログから消える(=しきい値内に収まる)ことを確認します。バッファ利用状況も合わせて見ると原因の切り分けが進みます。

本番環境で安全に有効化する閾値とオーバーヘッド

「本番でスロークエリログを常時ONにしてよいか」はよくある不安ですが、結論としてしきい値を適切に設定すれば常時有効で問題ありません。スロークエリログのオーバーヘッドは、しきい値を超えた少数のクエリを書き出すコストだけで、全クエリを記録する一般クエリログとは負荷が桁違いに小さいためです。

一方で long_query_time = 0(全クエリ記録)や log_queries_not_using_indexes の常時ONは避けるべきです。小規模テーブルへの無索引アクセスまで大量に記録され、ディスクを圧迫し、肝心の重いクエリが埋もれます。実務の出発点としては、本番は long_query_time = 1 前後から始め、ログが多すぎれば2〜3秒へ、少なすぎれば0.5秒へと調整します。短期間だけ long_query_time = 0 にして全クエリを採取し、pt-query-digest で棚卸しした後ですぐ戻す、という調査の使い方は有効です。

MySQL 8.0以降・MariaDBでの違いと注意点

スロークエリログの基本動作はバージョンをまたいで共通ですが、細部に差があります。MySQL 8.0.14以降では、ログ先頭の SET timestamp がクエリの「実行開始時刻」を示すようになりました(8.0.14より前はログに記録した時刻)。過去バージョンのログと時刻の意味が変わっているため、時系列を比較するときは版を意識します。また8.0.14で追加された log_slow_extra を有効にすると、Rows_examined などに加えて一時テーブル数やソート回数といった追加項目が記録でき、原因分析の手がかりが増えます。

MariaDBでもスロークエリログは利用でき、slow_query_loglong_query_time で同様に設定します。MariaDBは独自にクエリ単位でログ採取を制御する仕組みなどを持つため、細かなオプションは利用中のバージョンの公式ドキュメントで確認してください。出力項目や解析ツール(pt-query-digest)はMySQLと共通で使えます。

ログローテーションと保存期間の管理

スロークエリログは追記され続けるため、放置するとファイルが肥大化します。Linuxでは logrotate でローテーションするのが一般的で、ローテーション後にMySQLへログを開き直させる必要があります。スロークエリログのフラッシュはファイルを閉じて同じ名前で開き直す動作なので、新しいファイルに切り替えるには「現在のログをリネームしてから FLUSH LOGS;(または mysqladmin flush-logs、MySQL 8.0.19以降は SIGUSR1 シグナル)を実行する」順序にします。ディストリビューションによっては mysql-log-rotate スクリプトが付属する場合もあります。

保存期間は障害解析やトレンド把握の必要性で決めます。日次ローテーションで数週間分を保持し、容量が厳しければ圧縮保存する運用が現実的です。ログを残しておくと、性能劣化がいつから始まったかを後追いで調べられます。

よくある質問(FAQ)

スロークエリとは何ですか?

スロークエリとは、実行に時間のかかる遅いSQLそのものを指します。MySQLでは long_query_time で設定した秒数を超えたクエリが遅いと判定されます。その遅いクエリを記録する仕組みがスロークエリログで、両者は「遅いクエリ」と「その記録」という関係です。

long_query_timeの閾値は何秒にすべきですか?

デフォルトは10秒ですが、これは長すぎて多くの問題を取りこぼします。本番運用では1秒前後を出発点にし、ログ件数を見ながら0.5〜3秒で調整します。原因の棚卸しをする短期間だけ0秒(全クエリ)にして採取し、終わったら戻す使い方も有効です。

本番環境で有効にしても大丈夫ですか?

しきい値を適切に設定すれば常時有効で問題ありません。スロークエリログは超過した少数のクエリだけを書き出すため負荷は小さいです。ただし全クエリ記録(long_query_time=0)や無索引クエリの常時記録はログが膨れるため、調査時の一時利用にとどめます。

mysqldumpslowとpt-query-digestはどちらを使うべきですか?

手軽さなら同梱の mysqldumpslow、詳細分析なら pt-query-digest です。まず mysqldumpslow で合計時間の長いクエリの当たりを付け、継続チューニングや大量ログの精査では集計が豊富な pt-query-digest を使う、という併用が効率的です。

設定したのにスロークエリログが出力されません。

主な原因は、しきい値を超えるクエリが無い、出力先ファイルのパス・権限が不正、変更が新規接続にしか効いていない、の3つです。SHOW VARIABLES LIKE 'slow_query%'; で有効化とパスを確認し、SET GLOBAL long_query_time 変更後は接続を張り直してください。

関連記事

資料請求

RELATED POSTS 関連記事