SQLのパフォーマンス改善
このクエリ固有の話。一般的な推奨事項はいらない
あなたはデータベースの専門家です。このSQLは[テーブル名、約X万行]で実行に[所要時間]かかります。次をお願いします:1)最も疑わしいボトルネックを指摘する(実行計画を見る);2)最適化後のSQLを示す;3)必要なインデックスと、追加した場合の副作用(書き込みの遅化、容量)を説明する。「SELECT * を避けましょう」のような一般論は不要です。 ```sql [SQLを貼り付けてください] ```
使い方
修正後に実行計画のどこが変わったかを聞きましょう。それが分からないと、速くなった理由は分からないままです。
向いている場面
- 1 回のクエリが SLA(例:2 秒)を超え、テーブルが数百万行規模で、EXPLAIN の出力が手元にあるとき。
- レポートや定期ジョブで動く重いクエリを、リリース前にレビューするとき。
向いていない場面
- テーブルが数千行で 30 ミリ秒で返るなら、最適化の効果はマイナスです。手を付けません。
- 遅い原因がロック待ちやコネクションプールの枯渇なら、SQL ではありません。まず pg_stat_activity とスローログを見ます。
例
入力
SELECT o.id, o.created_at, u.email
FROM orders o
JOIN users u ON u.id = o.user_id
WHERE date_trunc('day', o.created_at) = '2026-03-01'
ORDER BY o.created_at DESC
LIMIT 50;
-- orders は約 800 万行、実行時間 6.4 秒
-- EXPLAIN は Seq Scan on orders を表示得られるもの
date_trunc によって created_at のインデックスが使えなくなっている点を挙げ、条件を `>= '2026-03-01' AND < '2026-03-02'` に変えるよう示します。次に ORDER BY がインデックスに乗らない点と、(created_at DESC) または (created_at, user_id) のインデックス、書き込みが遅くなる代償を説明します。書き換え後は Seq Scan が Index Scan になり、数百ミリ秒まで下がるはずです。
よくある誤用
- SQL だけを渡し、実行計画と実行時間を渡さないと、構文からボトルネックを推測するしかありません。
- 「最適化してください」とだけ頼むと、LEFT JOIN を INNER JOIN に変えて行数が変わるのに、その警告がないことがあります。
こう変えると効く
- `EXPLAIN (ANALYZE, BUFFERS)` の原文を貼ると、ボトルネックの判断が推測から数値の読み取りに変わります。
- 「まず 3 案とそれぞれのトレードオフを出し、選ぶのは私」と加えると、最も過激な書き換えを既定で選ばなくなります。