スロークエリ分析・改善・監視の進め方

中級 | 14分 で読める | 2026.06.27

公式ドキュメント

チューニングは推測で始めない

DBチューニングでよくある失敗は、遅い理由を見ずにインデックスを貼ることです。

スロークエリ改善は、発見、分析、仮説、修正、計測、監視の順で進めます。

速くなった気がする、ではなく、改善前後の数値で判断します。

全体の流れ

1. 遅いクエリを見つける
2. 実行頻度と影響範囲を見る
3. EXPLAIN / EXPLAIN ANALYZE を読む
4. 原因を仮説化する
5. SQLまたはインデックスを修正する
6. 改善前後を測る
7. 監視して再発を防ぐ

1回だけ遅いクエリと、毎秒大量に呼ばれる少し遅いクエリでは、優先度が変わります。

Step 1: 遅いクエリを見つける

PostgreSQLなら、スロークエリログや pg_stat_statements を使います。

見る指標:

  • 平均実行時間
  • p95 / p99
  • 呼び出し回数
  • 合計時間
  • 読み取りブロック数
  • 返却行数
  • 一時ファイル使用

平均だけでは見落とします。普段は速いが、特定条件で極端に遅いクエリもあります。

Step 2: EXPLAINを見る

まず実行計画を見ます。

EXPLAIN
SELECT *
FROM orders
WHERE user_id = 123
ORDER BY created_at DESC
LIMIT 20;

実測も見る場合:

EXPLAIN ANALYZE
SELECT *
FROM orders
WHERE user_id = 123
ORDER BY created_at DESC
LIMIT 20;

本番で EXPLAIN ANALYZE を使うと実際にクエリが実行されます。更新系SQLでは特に注意します。必要ならステージングやトランザクション内で確認します。

Step 3: よく見るポイント

実行計画では、次を見ます。

観点見ること
Seq Scan全件スキャンしていないか
Index Scan期待したインデックスが使われているか
rows推定行数と実測行数が大きくズレていないか
Sort大量ソートしていないか
Hash Join / Nested LoopJOIN方式が妥当か
Filterインデックスで絞れず後段で捨てていないか
Buffers読み取り量が大きすぎないか

特に、推定行数と実測行数のズレは重要です。統計情報が古い、条件の偏りが大きい、複合条件をDBが見積もれていない、などが原因になります。

Step 4: インデックスを考える

例のクエリ:

SELECT *
FROM orders
WHERE user_id = 123
ORDER BY created_at DESC
LIMIT 20;

候補:

CREATE INDEX idx_orders_user_created
ON orders(user_id, created_at DESC);

このインデックスは、user_id で絞り、created_at DESC の順で取り出す目的に合います。

インデックス設計では、次を確認します。

  • WHERE の等価条件
  • 範囲条件
  • ORDER BY
  • LIMIT
  • JOIN条件
  • 返す列
  • 書き込み頻度

インデックスは読み取りを速くする一方で、INSERT/UPDATE/DELETEを重くします。不要なインデックスは負債です。

Step 5: SQLを書き換える

インデックスだけでなく、SQL自体を変える方が効くこともあります。

例: 不要な SELECT * をやめる

SELECT id, total_amount, created_at
FROM orders
WHERE user_id = 123
ORDER BY created_at DESC
LIMIT 20;

例: N+1をJOINやINにする

SELECT *
FROM orders
WHERE user_id IN (1, 2, 3, 4);

例: 集計対象を先に絞る

SELECT user_id, COUNT(*)
FROM orders
WHERE created_at >= now() - interval '30 days'
GROUP BY user_id;

DBに大量データを返してアプリ側で絞る設計は、データ量が増えるほど厳しくなります。

Step 6: ロックと書き込みも見る

遅さはSELECTだけではありません。

見るもの:

  • ロック待ち
  • 長いトランザクション
  • 大量UPDATE
  • 外部キー制約チェック
  • インデックス更新負荷
  • コネクション枯渇

更新系の遅さは、単純なインデックス追加では解決しないことがあります。トランザクションを短くする、バッチサイズを小さくする、対象行を先に絞る、といった対策が必要です。

Step 7: 改善前後を測る

改善したら、必ず前後を比較します。

記録するもの:

変更前:
  avg 850ms
  p95 1800ms
  calls/min 120
  plan: Seq Scan + Sort

変更後:
  avg 40ms
  p95 90ms
  calls/min 120
  plan: Index Scan

ローカルで速くなっただけでは不十分です。ステージングや本番に近いデータ量で見ます。

Step 8: 監視する

チューニングは一度直して終わりではありません。

監視するもの:

  • スロークエリ件数
  • クエリ時間のp95 / p99
  • DB CPU
  • メモリ
  • ディスクI/O
  • コネクション数
  • ロック待ち
  • レプリカ遅延
  • エラー率

データ量や利用者が増えると、以前は速かったSQLが遅くなることがあります。スキーマ変更や機能追加でクエリパターンが変わることもあります。

よくあるアンチパターン

アンチパターン問題
遅いからとりあえずインデックス原因が違うと効かない
すべての列にインデックス書き込みが重くなる
SELECT * を放置不要なI/Oが増える
N+1を放置API全体が遅くなる
本番データ量で見ない小規模では問題が見えない
監視しない再発に気づけない
平均だけ見るp95/p99の悪化を見逃す

まとめ

スロークエリ改善は、感覚ではなく計測で進めます。

  • 遅いクエリを見つける
  • 実行頻度と影響範囲を見る
  • EXPLAINで実行計画を読む
  • インデックスとSQLの両方を検討する
  • ロックや書き込み負荷も見る
  • 改善前後を数値で比較する
  • 監視して再発を防ぐ

チューニング力は、SQL、テーブル設計、運用監視がつながった総合力です。

参考リソース

次に読む記事

← 一覧に戻る
PR
PR
PR
PR