アプリのレスポンスが急に遅くなった――その裏で、スロークエリが潜んでいるかもしれません。
スロークエリとは、実行に時間がかかるSQLクエリのこと。特にユーザー操作やAPIの応答に直結するクエリが遅いと、UXの低下やシステム負荷増大を招きます。最悪の場合、全体がダウンする引き金にもなりかねません。
本記事では、スロークエリの発見から改善まで、SQLパフォーマンスチューニングの基本と応用テクニックを解説します。
スロークエリはなぜ発生するのか?
まずは発生原因を理解しましょう。スロークエリは主に以下のような要因で起きます。
1. インデックスが効いていない
WHERE
句やJOIN
条件に使われているカラムにインデックスがなければ、フルテーブルスキャンになりやすい。
2. 不要なカラムのSELECT
SELECT *
は便利ですが、必要以上のデータを読み込むことでI/Oコストが増加します。
3. N+1クエリ問題
- ループ内で同じようなクエリを繰り返す構造。1回の操作で数百・数千のクエリが発行されることも。
4. 複雑すぎるJOINやサブクエリ
- 必要以上に多くのテーブルをJOINしていたり、非効率なネストされたサブクエリがある場合、計画が破綻しがちです。
スロークエリの見つけ方
1. DBのスロークエリログを使う
MySQLならslow_query_log
、PostgreSQLならpg_stat_statements
など、標準のログ機能を活用。
-- PostgreSQLでよく使われる統計表示
SELECT * FROM pg_stat_statements ORDER BY total_time DESC LIMIT 10;
このように、遅いクエリ・頻繁に実行されているクエリを特定できます。
2. アプリ側のAPMを活用する
New Relic、Datadog、ScoutなどのAPMツールは、API単位でSQLの実行時間を可視化してくれるため、どの処理で遅延が起きているかを把握しやすくなります。
基本のチューニングテクニック
1. 適切なインデックスの追加
- よく使う
WHERE
やORDER BY
の対象カラムにはインデックスを追加。 - 複数カラムでの検索には複合インデックスが有効。
CREATE INDEX idx_user_email ON users(email);
2. 不要なデータは取らない
SELECT *
を避け、必要なカラムだけ明示する。- LIMITやOFFSETを活用して絞り込んだクエリ設計を。
SELECT id, name FROM products WHERE category = 'book' LIMIT 20;
3. クエリの書き方を見直す
- 同じ目的でも、書き方によってパフォーマンスは大きく変わる。
- 例えば、サブクエリよりもJOINを使ったほうが高速な場合も。
-- 遅い例
SELECT name FROM users WHERE id IN (SELECT user_id FROM orders WHERE total > 100);
-- より速い例
SELECT u.name FROM users u JOIN orders o ON u.id = o.user_id WHERE o.total > 100;
4. 実行計画を確認する
EXPLAIN
やEXPLAIN ANALYZE
を使って、クエリの実行計画を可視化。- フルスキャンやネストループ、ソートの発生など、パフォーマンス低下の原因を特定できます。
応用テクニック:さらに一歩進んだ最適化
マテリアライズドビューの活用
複雑な集計やJOINを毎回実行せずに、結果をあらかじめキャッシュする手法。PostgreSQLではCREATE MATERIALIZED VIEW
で作成可能。
パーティショニングの導入
大量データのテーブルは、日付やIDなどで**分割(パーティション)**することで検索対象を絞り、パフォーマンスを向上させられます。
バッチ処理とリアルタイムの分離
リアルタイム処理に重い分析系クエリが混じると、全体が遅くなります。バッチ処理は専用のワーカや集計テーブルに分離しましょう。
最後に:SQLは“読めば読むほど速くなる”
SQLのパフォーマンス改善は、アプリの設計・ユーザー体験の改善・インフラコストの削減にもつながる極めて重要な技術です。
たった1行のSQLが、DBサーバを泣かせることもあれば、ユーザーを笑顔にすることもあります。
「なんとなく動くクエリ」から、「意図して速く書けるクエリ」へ。
スロークエリは放っておくと**“静かなる障害”**になります。
日々の観察と丁寧なチューニングで、あなたのDBはもっと速く、もっと賢くなるはずです。