「見えないボトルネック」を可視化する:pg_stat_user_tables との付き合い方
PostgreSQLを運用していて、「なぜか急にクエリが重くなった」「VACUUMが追いつかない」という壁にぶつかったとき、あなたならどこを最初に見ますか?
EXPLAIN ANALYZEで個別のクエリを追いかけるのも大切ですが、データベース全体の健康状態を語ってくれるのは、他でもない統計情報です。特に `pg_stat_user_tables` は、私たちが日々向き合っているデータの「呼吸」を可視化してくれる、極めて重要なビューです。
今日は、この統計情報を単なるモニタリング値としてではなく、アーキテクチャの文脈からどう読み解き、どうトラブルシューティングに活かすかについて、少し深い話をしようと思います。
なぜ、seq_scan が「悪」ではないのか
まず、このビューにある `seq_scan` や `idx_scan` の値をどう解釈するかです。
多くのエンジニアが「seq_scan が多いのはインデックスが足りないからだ」と考えがちですが、それは少し短絡的です。PostgreSQLのオプティマイザは、テーブルサイズが極端に小さい場合、インデックスを引くよりシーケンシャルスキャンでメモリに乗せてしまった方が速いと判断します。
ここで注目すべきは、`seq_scan` の値そのものよりも、「想定外のタイミングで seq_scan が急増していないか」という変化の兆候です。統計情報のモニタリングを自動化しているなら、特定テーブルのこの値がスパイクした瞬間、何が起きたのかを追うだけで、アプリケーションの意図しないクエリ発行や、統計情報の陳腐化によるプランナーの迷走を突き止めることができます。
ライブタプルとデッドタプル:MVCCの「残滓」を読み解く
`n_live_tup` と `n_dead_tup`。このペアこそが、PostgreSQLのMVCC(多版同時実行制御)の本質を物語っています。
ここでのトラブルシューティングの勘所は、「デッドタプルが蓄積する速度(生成率)と、autovacuumの処理能力の乖離」を見ることです。
- n_dead_tup が異常に高い: これはVACUUMの閾値設定が甘いか、あるいは長時間実行されているトランザクションが存在し、VACUUMが古いタプルを物理削除できない「ゴミ掃除の詰まり」を起こしている可能性が高いです。
- n_mod_since_analyze との相関: 更新頻度が激しいのに `n_mod_since_analyze` が放置されていると、統計情報が実態と乖離し、クエリプランが劣化します。
もしあなたが「なぜか最近、クエリが遅い」と感じているなら、一度 `pg_stat_user_tables` を見てみてください。`n_dead_tup` が肥大化し、オプティマイザがテーブルのサイズを見誤っているというケースは、現場で驚くほどよくある「隠れた原因」です。
統計情報の「鮮度」を疑う勇気
PostgreSQLの統計情報は、基本的に `autovacuum` や `ANALYZE` によって更新されます。しかし、大量のデータを一度に流し込んだり、極端な偏りを持つデータを更新したりすると、統計情報の更新が追いつかなくなることがあります。
現場で私がよくやる手法は、トラブルが発生した際、あえて `ANALYZE` を手動で実行し、その後すぐに `pg_stat_user_tables` の該当テーブルの統計値とプランナの挙動を比較することです。
「数値が正しいから大丈夫」ではなく、「この数値が、今のDBの物理レイアウトを正しく反映しているか?」を疑う。この視点を持つだけで、トラブルシュートの精度は劇的に変わります。
最後に:数値を「ストーリー」に変換する
`pg_stat_user_tables` は、単なるテーブルの一覧ではありません。それは、アプリケーションがどのようにデータと対話しているかを描き出す「ログ」です。
- `n_tup_ins`, `n_tup_upd`, `n_tup_del` の比率から、そのテーブルが「追記型」なのか「更新型」なのかを知る。
- `last_vacuum`, `last_autovacuum` から、保守運用が健全に行われているかを確認する。
こうして数字の裏にある「挙動」を想像できるようになると、データベースエンジニアとしての景色が変わってきます。
皆さんの運用するPostgreSQLは、今日どのような「呼吸」をしていますか? ぜひ、今一度 `pg_stat_user_tables` を眺めてみてください。そこに、まだ見ぬボトルネックのヒントが隠されているかもしれません。
—
それでは、また次回の記事でお会いしましょう。Happy Hacking!
コメント