MySQLスロークエリログの設定と読み方:mysqldumpslowで分析

black flat screen computer monitor SQL

MySQLでクエリが遅い原因を探るとき、最初に頼るべきツールが「スロークエリログ(slow query log)」です。一定時間を超えたSQLを自動記録してくれるため、どのクエリが性能のボトルネックになっているかを効率よく特定できます。この記事では、スロークエリログの有効化に必要なmy.cnf設定から、ログ出力のフォーマットの読み方、mysqldumpslowを使ったログの集計・分析方法まで、MySQL 8.0を前提に実例つきで解説します。

このシナリオで考える

本記事では、ECサイトの注文管理システムを想定します。ordersテーブルに数百万行のデータがあり、特定のクエリが「なぜか重い」という状況を例に使います。

CREATE TABLE orders (
  id         BIGINT        PRIMARY KEY AUTO_INCREMENT,
  user_id    INT           NOT NULL,
  status     VARCHAR(20)   NOT NULL,
  total      DECIMAL(10,2) NOT NULL,
  created_at DATETIME      NOT NULL
);

このテーブルへの検索クエリの中に、スロークエリが潜んでいる想定です。スロークエリログを有効にすることで、問題のあるクエリを自動的にリストアップできます。

スロークエリログの有効化と設定

スロークエリログはデフォルトで無効になっています。有効化には、設定ファイルへの追記か、動的な変数変更の2つの方法があります。

主要な設定項目の意味を先にまとめておきます。

変数名 意味 推奨値
slow_query_log スロークエリログの有効/無効 1(有効)
slow_query_log_file ログファイルの出力先パス /var/log/mysql/slow.log
long_query_time 記録するクエリの閾値(秒)。デフォルトは10 1〜2
log_queries_not_using_indexes インデックスを使わないクエリも記録する 1(調査時に有効)
log_output 出力先。FILEまたはTABLE(mysql.slow_log) FILE(デフォルト)

long_query_timeのデフォルトは10秒と長めです。実務では1〜2秒に下げておくと、遅いクエリをより広く拾えます。

my.cnfによる永続的な設定

再起動をまたいでも設定を維持したい場合は、/etc/mysql/my.cnf(または/etc/my.cnf)に追記します。

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

追記後はMySQLを再起動して設定を反映させます。

sudo systemctl restart mysql

再起動なしで動的に変更する

本番環境で再起動が難しい場合は、SET GLOBALで即時反映できます。

SET GLOBAL slow_query_log     = 'ON';
SET GLOBAL long_query_time    = 1;
SET GLOBAL log_queries_not_using_indexes = 1;

ただし動的変更はMySQLを再起動すると元に戻ります。my.cnfへの追記も合わせて行うのを忘れないようにしましょう。現在の設定値はSHOW VARIABLESで確認できます。

SHOW VARIABLES LIKE 'slow_query%';
SHOW VARIABLES LIKE 'long_query_time';

ログの出力フォーマットを読む

スロークエリログには、閾値を超えたクエリが次のような形式で書き出されます。

# Time: 2026-06-16T03:45:12.123456Z
# User@Host: app_user[app_user] @ [192.168.1.10]  Id: 1042
# Query_time: 2.345678  Lock_time: 0.000234  Rows_sent: 1  Rows_examined: 480000
SET timestamp=1750042312;
SELECT * FROM orders WHERE status = 'pending' AND total > 1000;

各フィールドの意味は次のとおりです。

フィールド 意味
Time クエリが完了した時刻(UTC)
User@Host 実行ユーザーとホスト名・IPアドレス
Query_time クエリの実行時間(秒)
Lock_time ロック取得にかかった時間(秒)
Rows_sent クライアントに返した行数
Rows_examined MySQL内部で走査した行数

注目すべきはRows_examinedです。上の例では48万行を走査して1行しか返していません。インデックスが効いていれば走査行数はずっと少なくなるはずで、この乖離が大きいほどチューニングの余地があるサインになります。

また、Lock_time が Query_time の大半を占める場合はクエリ自体の問題ではなく、排他ロックの待ちが原因の可能性があります。この場合はインデックスより先にトランザクションの設計を見直すべきです。

mysqldumpslowで集計・分析する

ログが大きくなると目視での確認は現実的ではありません。mysqldumpslowコマンドを使うと、同じ構造のクエリをグループ化してサマリーを表示できます。数値やリテラル文字列はN/'S'に抽象化されるため、パラメータの違いを無視して同じクエリをまとめてくれます。

基本の使い方

mysqldumpslow /var/log/mysql/slow.log

デフォルトでは平均実行時間(at)の降順で上位10件が表示されます。出力例は次のとおりです。

Count: 42  Time=2.35s (98s)  Lock=0.00s (0s)  Rows=1.0 (42), app_user@192.168.1.10
  SELECT * FROM orders WHERE status = 'S' AND total > N

この例では、同じ構造のクエリが42回実行され、合計98秒かかっていることが読み取れます。

よく使うオプション

オプション 意味
-s t クエリ時間の合計が大きい順(total time)
-s at クエリ時間の平均が大きい順(average time)※デフォルト
-s c 実行回数が多い順(count)
-s r 走査行数の平均が大きい順(rows examined)
-t N 上位N件のみ表示
-g "pattern" クエリ内容でgrepフィルタ

実務でよく使う組み合わせを示します。

# 実行時間の合計が長い上位5クエリ(サーバ負荷の元凶を探す)
mysqldumpslow -s t -t 5 /var/log/mysql/slow.log

# 実行回数が多い上位5クエリ(頻発する問題クエリを探す)
mysqldumpslow -s c -t 5 /var/log/mysql/slow.log

# ordersテーブルに関するクエリのみ絞り込む
mysqldumpslow -g "orders" /var/log/mysql/slow.log

「1回しか実行されないが5秒かかる」クエリは-s tで、「0.2秒だが1万回実行されて合計で大量のCPUを使う」クエリは-s cで発見できます。両面から確認するのが効果的です。

よくある落とし穴と注意点

  • long_query_time=10のまま運用しない:デフォルトの10秒では相当重いクエリしか記録されません。まず1〜2秒に下げましょう。チューニング調査時には0に設定して全クエリを一時的に記録する方法も有効です。
  • ログファイルの肥大化に注意log_queries_not_using_indexes=1を有効にすると、インデックスを使わない全クエリが記録されてディスクを圧迫することがあります。本番での常時有効化は慎重に検討し、logrotateでのローテーションも設定しておきましょう。
  • Rows_examined が大きい = インデックス不足のサイン:Rows_sent が小さいのに Rows_examined が大きい場合、フルスキャンが起きている可能性があります。EXPLAINで実行計画を確認してインデックス追加を検討しましょう。
  • ログファイルのパーミッションを確認するslow_query_log_fileに指定したパスにMySQLプロセスの書き込み権限がないとログが記録されません。ファイルが存在しない場合はtouchしてからchown mysql:mysqlで所有者を設定します。

まとめ

スロークエリログは、MySQLの性能問題を発見するための最初の手がかりです。long_query_timeを1〜2秒に設定して有効化し、mysqldumpslowで合計時間・実行回数の両面から重点クエリを絞り込みましょう。ログで見つけたクエリはEXPLAINで実行計画を確認してインデックス設計に活かすのが次のステップです。

参考リンク

アイキャッチ画像: Photo by WebFaster on Unsplash

タイトルとURLをコピーしました