こんにちは、かつコーチです。
前回はEXPLAINで個別クエリの実行計画を読む方法を解説しましたが、実務ではまず「どのクエリが遅いのか」を見つけるところから始まります。
そこで活躍するのがスロークエリログです。
今回は、スロークエリログの有効化から、たまったログをどう読み解いて改善につなげるかまでを解説します。
スロークエリログとは
遅いクエリだけを記録する仕組み
スロークエリログは、指定した秒数(long_query_time)を超えて実行されたクエリだけを記録するMySQLの機能です。
本番環境では日々大量のクエリが実行されているため、全クエリのログを取るのは現実的ではなく、「一定時間より遅いクエリだけ」に絞って可視化するのが実務での基本的な使い方です。
有効化のための設定
-- 現在の設定を確認する
SHOW VARIABLES LIKE 'slow_query_log%';
SHOW VARIABLES LIKE 'long_query_time';
-- スロークエリログを有効化し、1秒を超えるクエリを記録対象にする
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
SET GLOBAL slow_query_log_file = '/var/log/mysql/mysql-slow.log';
my.cnf(設定ファイル)に恒久的な設定として書く場合は、次のように記述します。
# /etc/mysql/my.cnf などに追記
[mysqld]
slow_query_log = 1 slow_query_log_file = /var/log/mysql/mysql-slow.log long_query_time = 1 log_queries_not_using_indexes = 1
log_queries_not_using_indexesを有効にすると、実行時間が短くてもインデックスを使っていないクエリまで記録できるため、潜在的な問題の早期発見に役立ちます。
スロークエリログの読み方
ログの基本フォーマット
スロークエリログには、1クエリごとに次のような情報が出力されます。
# Time: 2026-09-02T10:15:32.123456Z
# User@Host: app_user[app_user] @ [10.0.1.15]
# Query_time: 3.482156 Lock_time: 0.000123 Rows_sent: 1 Rows_examined: 452301
SET timestamp=1788000000;
SELECT * FROM orders WHERE status = 'paid' ORDER BY created_at DESC LIMIT 10;
確認すべきポイントは次の3つです。
Query_time:クエリの実行時間そのものRows_examined:実際にスキャンした行数(インデックスが効いていないと大きくなる)Rows_sent:クライアントに返した行数
Rows_examinedがRows_sentに比べて極端に大きい場合、大量の行をスキャンして絞り込んでいることになり、インデックス不足が疑われます。
先ほどの例では、1件返すために45万行以上をスキャンしており、典型的な「インデックス不足によるフルスキャン」のパターンです。
mysqldumpslowで集計する
本番環境ではログが大量にたまるため、1件ずつ目視するのは非効率です。
MySQL付属のmysqldumpslowコマンドを使うと、似たクエリをパターンごとにまとめ、実行回数や平均時間でソートして集計できます。
# 平均実行時間が長い順に上位10件を表示
mysqldumpslow -s at -t 10 /var/log/mysql/mysql-slow.log
# 実行回数が多い順に上位10件を表示
mysqldumpslow -s c -t 10 /var/log/mysql/mysql-slow.log
「たまに1回だけ極端に遅いクエリ」より「毎回そこそこ遅く、実行回数が多いクエリ」の方が、全体のサーバー負荷への影響は大きいことが多いため、-s c(実行回数順)でも一度確認しておくことをおすすめします。
ログから改善につなげる流れ
改善の優先順位の付け方
スロークエリログを集計したら、次の観点で改善対象の優先順位を付けます。
- 実行回数が多く、かつ平均実行時間も長いクエリ(総負荷が最大)
Rows_examinedが突出して大きいクエリ(インデックス改善の効果が出やすい)- 実行頻度は低いが、タイムアウトなどユーザー体験に直結するクエリ
優先順位を付けずに目についたクエリから手をつけると、影響の小さい改善に時間を使ってしまうことがあるため、まず集計結果全体を俯瞰することが重要です。
私が本番環境で経験したスロークエリ対応
以前、深夜バッチの後に管理画面が急に重くなるという相談があり、スロークエリログをmysqldumpslow -s cで集計したところ、Rows_examinedが数十万件に達する集計クエリが1日に数千回実行されていることが判明しました。
EXPLAINで確認するとtype: ALLのフルテーブルスキャンになっており、集計対象のcreated_atとstore_idを組み合わせた複合インデックスが存在していませんでした。
-- 原因の集計クエリ(簡略化)
SELECT store_id, COUNT(*) FROM sales
WHERE created_at >= '2026-09-01' AND store_id = 12
GROUP BY store_id;
-- 複合インデックスを追加
CREATE INDEX idx_sales_store_created ON sales (store_id, created_at);
インデックス追加後は同じクエリのQuery_timeが3秒台から0.05秒台まで改善し、管理画面の体感速度も明らかに改善しました。
このとき学んだのは、体感の「重い」を頼りに調査するより、スロークエリログの数値で優先度を付けた方が、原因特定までの時間を大幅に短縮できるということです。
まとめ
この記事のポイント
- スロークエリログは
long_query_timeを超えたクエリだけを記録し、log_queries_not_using_indexesと併用すると潜在的な問題も見つけやすい - ログの
Query_time・Rows_examined・Rows_sentから、インデックス不足の可能性を判断できる mysqldumpslowで実行時間順・実行回数順に集計し、優先順位を付けてから改善に着手する- 実行回数が多く総負荷が大きいクエリから対応する方が、全体のパフォーマンス改善への効果が大きい
- 体感の「重さ」だけに頼らず、ログの数値をもとに調査すると原因特定が速くなる
次に読むべき記事
「インデックス・パフォーマンス編」は今回で完結です。
次回からは「レプリケーション・バックアップ編」に入り、まずは「MySQLレプリケーションの基本:仕組みとメリット」を解説します。
タグ: MySQL, 上級者向け, パフォーマンス
