リアルなプロジェクトで開発してると、アプリに同時に何千人ものユーザーがアクセスしてくることがあるよね。みんながDBにクエリを投げて、データを追加したり読んだり更新したり... で、気づいたらサーバーが「うぅ...」って悲鳴を上げてる。これはクエリが全然最適化されてないサイン。紙の上では「イケてる」クエリも、実際にはパフォーマンスの大惨事になることもある。そんな時に登場するのがpg_stat_statementsだよ。
pg_stat_statementsを使うと、こんなことができる:
- 遅いクエリを追跡できる。
- どのクエリが何回実行されたか分かる。
- それぞれのクエリにどれだけ時間がかかったか分かる。
- クエリの平均実行時間が見える。
- アプリ全部書き直すみたいな致命的ミスを防げる!
pg_stat_statementsの構造を見てみよう
拡張機能を有効化すると、DBにpg_stat_statementsっていう特別なビューができる。ここに実行されたクエリのデータが全部入ってる。まずは中身を見てみよう:
SELECT * FROM pg_stat_statements LIMIT 1;
結果はこんな感じ(シンプルにしてるよ):
| query | calls | total_time | rows | shared_blks_read |
|---|---|---|---|---|
| SELECT * FROM students | 500 | 20000 ms | 5000 | 100 |
ざっくり説明すると:
query— SQLクエリそのもの。calls— このクエリが何回実行されたか。total_time— このクエリが合計でどれだけ時間を使ったか。rows— クエリが返した行数。shared_blks_read— 読み込んだブロック数(キャッシュ使ってなければディスクから読むよ)。
結果を分析しよう
さて、pg_stat_statementsが有効になったら、遅いクエリをどうやって見つけるか見てみよう。
一番遅いクエリを探す
どのクエリが一番時間を食ってるか調べるには、こんなクエリを使う:
SELECT query, total_time, calls, mean_time
FROM pg_stat_statements
ORDER BY total_time DESC
LIMIT 5;
ここで:
mean_time— 1回あたりの平均実行時間(total_time / calls)。ORDER BY total_time DESC— 合計実行時間でソートしてる。
よく実行されるクエリを探す
問題は遅いクエリだけじゃなくて、実行回数が多すぎるクエリにもある。例えば:
SELECT query, calls
FROM pg_stat_statements
ORDER BY calls DESC
LIMIT 5;
クエリの最適化
- インデックスを使おう
特定のカラムでクエリが遅いなら、そのカラムにインデックスがあるか確認しよう。例えば、studentsテーブルに大量の行があって、last_nameカラムによくアクセスするなら、インデックスを作るといい:
CREATE INDEX idx_students_last_name ON students (last_name);
- クエリを書き直そう
例えば、SELECT * FROM orders WHERE amount > 1000みたいなクエリがめっちゃ遅い場合、全部のカラムを取るんじゃなくて必要なカラムだけ選ぼう:
SELECT order_id, amount FROM orders WHERE amount > 1000;
統計情報のリセット
最適化後の新しい結果だけ見たいときは、pg_stat_statementsのデータをリセットしよう。コマンドはこれ:
SELECT pg_stat_statements_reset();
電卓の「リセット」ボタンみたいな感じ。実行したら統計がまたゼロから集計されるよ。
問題クエリの探し方
例えば、君が大学のDB管理者で、学生たちが「マイページが全然開かない!」って大量にクレームしてきたとしよう。そこでpg_stat_statementsをチェックする:
ステップ1: 一番遅いクエリを探す
SELECT query, total_time, calls, mean_time
FROM pg_stat_statements
ORDER BY total_time DESC
LIMIT 1;
例えばSELECT * FROM students WHERE status = 'active'みたいなクエリが30秒もかかってるのを発見。「やばっ」ってなるよね。すぐ対策しよう。
ステップ2: インデックスを確認 studentsテーブルを見てみたら、statusカラムにインデックスが無いことに気づく。すぐ追加しよう:
CREATE INDEX idx_students_status ON students (status);
ステップ3: 結果を確認 最適化した後、もう一度pg_stat_statementsを見てみると、クエリが0.5秒で終わるようになってる。やったね!
pg_stat_statementsでよくあるミス
クエリ分析で管理者がやりがちなミス:
- 拡張機能が有効化されてない。
shared_preload_librariesにpg_stat_statementsを追加し忘れると、統計が全然集まらないよ。 - インデックスを無視する。クエリが遅い時、インデックス追加で一発解決することも多い。
- 統計のリセットをしない。
pg_stat_statements_reset()を実行しないと、古いデータが混ざって今の状況が分かりにくくなる。
pg_stat_statementsを使うのは、DBのGPSナビみたいなもん。どこで「渋滞」してるか教えてくれるし、どうやって回避するかもヒントをくれる。ちゃんと設定して使いこなせば、DBのパフォーマンスがグッと良くなるよ!
GO TO FULL VERSION