MySQLで実行時間の長いSQL文をログに出力するには、slow_query_loglong_query_timeを設定する。
インデックスを使わないクエリまで対象を広げる場合はlog_queries_not_using_indexesもあわせて使う。

参考: 【PostgreSQL】log_min_duration_statementでスロークエリをログに出力する

slow_query_logとlong_query_timeとは

slow_query_logは、スロークエリログの出力を有効・無効にするパラメータである。
long_query_timeは、何秒以上かかったSQL文をスロークエリとみなすかを指定するパラメータである。

デフォルトではslow_query_logOFFlong_query_time10秒である。

mysql> SHOW VARIABLES LIKE 'slow_query_log';
+----------------+-------+
| Variable_name  | Value |
+----------------+-------+
| slow_query_log | OFF   |
+----------------+-------+

mysql> SHOW VARIABLES LIKE 'long_query_time';
+------------------+-----------+
| Variable_name    | Value     |
+------------------+-----------+
| long_query_time  | 10.000000 |
+------------------+-----------+

PostgreSQLのlog_min_duration_statementはミリ秒単位で1つのパラメータにしきい値を設定するが、MySQLは有効化フラグ(slow_query_log)としきい値(long_query_time、秒単位)が別パラメータになっている。

一時的に設定する

SET GLOBALで実行中のサーバーに対して設定を変更できる。

SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 0.2;

上記の例では、0.2秒以上かかったSQL文がスロークエリログへ出力される。
0.3秒かかるクエリを実際に実行すると、以下のようにログファイルへ出力される。

mysql> SELECT SLEEP(0.3);
# Time: 2026-08-20T23:48:05.607068Z
# User@Host: root[root] @ localhost []  Id:    11
# Query_time: 0.304440  Lock_time: 0.000000 Rows_sent: 1  Rows_examined: 1
SET timestamp=1787269685;
SELECT SLEEP(0.3);

Query_timeが実行時間、Lock_timeがロック待ち時間、Rows_sentが返した行数、Rows_examinedが内部で走査した行数である。
SET GLOBALによる変更はサーバーの再起動で失われるが、実行中の全セッションへ即座に反映される点はPostgreSQLのSET(セッション単位)と異なる。

ログの出力先を確認する

スロークエリログの出力先ファイルはslow_query_log_fileで確認する。

mysql> SHOW VARIABLES LIKE 'slow_query_log_file';
+-----------------------+--------------------------------------+
| Variable_name         | Value                                |
+-----------------------+--------------------------------------+
| slow_query_log_file   | /var/lib/mysql/[hostname]-slow.log   |
+-----------------------+--------------------------------------+

デフォルトでは[hostname]-slow.logのようにホスト名を含んだファイル名がデータディレクトリ配下に作られる。
log_output変数をTABLEに変更すると、ファイルの代わりにmysql.slow_logテーブルへ記録できる。

SET GLOBAL log_output = 'TABLE';
mysql> SELECT start_time, query_time, sql_text FROM mysql.slow_log ORDER BY start_time DESC LIMIT 1\G
*************************** 1. row ***************************
start_time: 2026-08-20 23:48:22.743863
query_time: 00:00:00.051252
  sql_text: SELECT SLEEP(0.05)

SQLで直接検索・集計できるようになるため、ログファイルをパースするより手軽に分析できる。
ただし書き込みコストがファイル出力より高くなるため、本番環境で常用する場合は影響を確認する。

log_queries_not_using_indexesでインデックス未使用のクエリも記録する

log_queries_not_using_indexesONにすると、long_query_timeを超えていなくても、インデックスを使わないクエリがスロークエリログに記録される。

SET GLOBAL log_queries_not_using_indexes = ON;

主キーidと、インデックスのないvalカラムを持つtestdb.t1テーブルへ5,000行を投入した状態で、valカラムを条件に検索すると、実行時間が1ミリ秒未満でもログに出力される。

mysql> SELECT * FROM testdb.t1 WHERE val = 50;
# Time: 2026-08-20T23:48:13.576989Z
# User@Host: root[root] @ localhost []  Id:    14
# Query_time: 0.000682  Lock_time: 0.000007 Rows_sent: 50  Rows_examined: 5000
SET timestamp=1787269693;
SELECT * FROM testdb.t1 WHERE val = 50;

Rows_examinedが5000であるのに対しRows_sentは50であり、テーブルの大部分を走査してから絞り込んでいることが分かる。
実行時間だけでは見つけにくい非効率なクエリを洗い出す際に有効である。

恒久的に設定する

サーバー全体の設定として恒久的に変更するには、my.cnfに以下のように記述する。

[mysqld]
slow_query_log = 1
long_query_time = 1
log_queries_not_using_indexes = 1

これらのパラメータはすべて動的変数であるため、SET PERSISTでも設定でき、サーバーの再起動は不要である。

SET PERSIST slow_query_log = ON;
SET PERSIST long_query_time = 1;

参考: 【MySQL】my.cnfの場所を探す
参考: 【MySQL】再起動が必要な設定を見分ける

mysqldumpslowで集計する

スロークエリログをファイルに出力している場合、mysqldumpslowコマンドでクエリごとに集計できる。
プレースホルダの違いを吸収し、同じパターンのクエリをまとめて実行回数・平均の実行時間順に表示する。

$ mysqldumpslow -s t -t 10 /var/lib/mysql/[hostname]-slow.log

参考: mysqldumpslowでMySQLのスロークエリを集計する

運用時の注意点

long_query_timeを短い値に設定するほど、ログに出力されるSQL文が増える。
ログの出力自体にもI/Oコストがかかるため、値を小さくしすぎるとサーバー負荷が上がる原因になる。

log_queries_not_using_indexesはインデックス未使用のクエリを網羅的に記録する分、対象システムによってはログの出力量が急増しやすい。
まずはlong_query_timeだけを数百ミリ秒程度に設定して傾向を把握し、必要に応じてlog_queries_not_using_indexesを有効にするとよい。

参考