なぜ、あなたのDBは「遅い」のか? pg_stat_statementsを使いこなすための深層心理と技術論
現場でパフォーマンスチューニングをしていると、必ずと言っていいほど直面する問いがあります。「結局、どのクエリが一番悪さをしているのか?」という問いです。
PostgreSQLを運用していて、この答えに窮するようではエンジニアとして少し心許ない。そんな時、我々が真っ先に手を伸ばすのが `pg_stat_statements` です。ただ、これを単に「遅いクエリを見るためのツール」として使っているなら、非常にもったいない。
今日は、このモジュールを単なる便利ツールから「DBの心臓部を透視するためのレンズ」へと昇華させる話をしましょう。
pg_stat_statementsの「魔法」の裏側
まず、この拡張がどうやって動いているのか、その内部構造を理解しておく必要があります。
`pg_stat_statements` は、PostgreSQLのフック機構(`ExecutorStart_hook` など)を利用して、クエリの実行プランが生成される直前、あるいは実行が終了した直後の情報を拾い上げています。特筆すべきは、「正規化(Normalization)」のプロセスです。
`SELECT FROM users WHERE id = 1;` と `SELECT FROM users WHERE id = 100;` は、DB内部では全く別のクエリとして扱われるのが自然ですが、このモジュールはこれらを `SELECT FROM users WHERE id = ?;` という一つのテンプレートとして集約します。
この「定数部分を削ぎ落として構造を抽出する」という処理が、共有メモリ上で極めて軽量に行われている。だからこそ、高負荷な本番環境でもオーバーヘッドを最小限に抑えつつ、統計情報を蓄積できるわけです。
チューニングの「勘所」は、どこにあるか?
皆さんは `pg_stat_statements` を見て、どのカラムを一番重視しますか? 多くの人が `total_exec_time` や `mean_exec_time` を見がちですが、私はいつも `mean_exec_time` と `calls` の積、そして `shared_blks_hit` に対する `shared_blks_read` の比率 に注目します。
1. 「回数 × 時間」の罠
1回の実行に1秒かかるクエリが10回走るのと、1msのクエリが10万回走るのでは、システムへのインパクトは後者の方が遥かに大きい。`mean_exec_time` だけを見ていては、DBのCPU負荷を食いつぶしている「チリツモ」クエリを見逃してしまいます。
2. キャッシュヒット率の逆算
`shared_blks_read`(ディスクから読み込んだブロック数)が `shared_blks_hit`(メモリからヒットした数)に対して異常に多い場合、それはクエリの書き方が悪いのか、単にインデックスが足りないのか、あるいは `work_mem` が不足していて一時ファイルへの書き込みが発生しているのか。この比率を見るだけで、ボトルネックの正体はおおよそ見当がつきます。
パフォーマンストラブルシューティングの極意
私がトラブルシューティングを行う際、必ずやる手順を共有しましょう。
1. `pg_stat_statements_reset()` を実行するタイミングを制御する
デプロイやバッチ実行の前後でリセットし、特定の処理がどのようなクエリを生成しているのかを「差分」で追う。これが一番の近道です。
2. `queryid` の相関関係を追う
`pg_stat_statements` が出力する `queryid` は、`pg_stat_activity` や `pg_locks` と紐付け可能です。現在進行形でロック待ちをしているクエリが、過去にどれほどの負荷をかけてきたのか。これらを統合して分析することで、「今の遅延」を「過去の傾向」から論理的に説明できるようになります。
3. `local_blks` の追跡
特に一時テーブルやソート処理で発生する `local_blks` の増加は、アプリケーションレベルの設計不備を物語ります。ここを放置してインデックスだけで解決しようとするのは泥沼の始まりです。
最後に:ツールに踊らされるな
`pg_stat_statements` は確かに強力ですが、あくまで「現状を映す鏡」に過ぎません。
最も重要なのは、統計情報から「なぜこのクエリがこの実行計画を選んだのか」「なぜこのクエリが大量のディスクI/Oを必要としているのか」を推論する、皆さんのエンジニアとしての直感と知識です。
DBのチューニングは、数学のような美しさと、考古学のような泥臭さが同居しています。ぜひ、このツールを使い倒して、PostgreSQLの深淵を覗いてみてください。そこには、まだあなたが知らない「クエリの最適解」が眠っているはずです。
さて、そろそろ共有メモリの統計を眺める時間です。次はどんなボトルネックが待っているのか、楽しみですね。
コメント