【実務・中級編】 pg_stat_database – PostgreSQL

「DBが急に重い?」と焦る前に。PostgreSQLの健康診断『pg_stat_database』活用術

現場で運用をしていると、必ず一度は遭遇する「DBがなんか重い気がする…」という相談。そんなとき、あなたならどこから調査を始めますか?

いきなり `EXPLAIN ANALYZE` で特定のクエリを深掘りするのも大切ですが、まずは「全体像」を俯瞰することが解決への近道です。今回は、PostgreSQLの統計情報ビューの中でも、僕がトラブルシューティングの初手で必ず確認する『`pg_stat_database`』について、現場目線で深掘りしてみようと思います。

—

`pg_stat_database` って結局なに?

一言で言えば、「データベースの健康診断書」です。

特定のテーブルやインデックスではなく、DBインスタンス全体(あるいは各データベース単位)で、どれくらいのトランザクションが走り、どれくらいディスクを読みに行っているか。そんな「DB全体の呼吸の様子」がひと目で分かるビューですね。

まずは、どんな値が取れるのか見てみましょう。

SELECT
datname,
xact_commit,
xact_rollback,
blks_read,
blks_hit,
tup_returned,
tup_fetched
FROM pg_stat_database
WHERE datname = ‘your_database_name’;

これを見るだけで、「このDBは読み取りが中心なのか、書き込みが激しいのか」「キャッシュは効いているか」といった傾向が手に取るようにわかります。

—

現場で見るべき3つのポイント

教科書通りの説明は公式ドキュメントに任せるとして、僕が現場で「ここを必ずチェックする」というポイントを紹介します。

1. コミットとロールバックの比率(xact_commit / xact_rollback)

アプリから見ていて「DBの応答が遅い」というとき、このロールバック数が異常に増えていないかを確認します。
もし `xact_rollback` が急増していたら、アプリケーション側の例外処理が頻発している証拠です。DBが悪いのではなく、アプリ側のロジック(重複キー違反やバリデーションエラーなど)がDBを叩きすぎている、という切り分けができます。

2. キャッシュヒット率の算出(blks_hit / blks_read)

DBエンジニアの腕の見せ所とも言えるのがこれ。

  • `blks_hit`: メモリ(バッファキャッシュ)から取得できた回数
  • `blks_read`: ディスクから読み込んだ回数

計算式は `blks_hit / (blks_hit + blks_read)`。これが極端に低い(例えば90%以下など)場合、メモリが足りていないか、インデックスが効いていないフルスキャンが多発している可能性が高いです。「メモリを増やすべきか、クエリを直すべきか」の判断材料になります。

3. 読み取った行数と処理した行数(tup_returned / tup_fetched)

ここも重要です。`tup_returned` はスキャンした行数、`tup_fetched` は実際に取り出した行数です。
この差が大きすぎる場合、「10万行スキャンしたけど、使ったのは1行だけ」みたいな非効率なクエリが裏で動いていることを示唆しています。インデックスの改善や、不要なテーブル結合の見直しが必要なサインですね。

—

実践:運用ツールを作ってみよう

統計情報は「今の瞬間」を見るだけでは不十分です。負荷の推移を知るために、僕は定期的にスナップショットを撮る簡単なスクリプトを仕込んでいます。

例えば、`pg_stat_database` はDB再起動や統計情報の強制リセットで値がクリアされてしまうので、以下のようなテーブルを作って定期実行しておくと便利ですよ。

— 統計情報の蓄積用テーブル
CREATE TABLE stats_history (
captured_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
datname TEXT,
xact_commit BIGINT,
xact_rollback BIGINT,
blks_read BIGINT,
blks_hit BIGINT
);

— これをcronやpg_cronで回す
INSERT INTO stats_history (datname, xact_commit, xact_rollback, blks_read, blks_hit)
SELECT datname, xact_commit, xact_rollback, blks_read, blks_hit
FROM pg_stat_database
WHERE datname = ‘production_db’;

こうしておけば、「昨日から今日にかけて、急に `blks_read` が跳ね上がっているな。昨日のデプロイの影響かな?」といった因果関係が、数字で語れるようになります。

—

最後に:数字に振り回されないために

『`pg_stat_database`』は非常に強力ですが、あくまで「傾向を見るためのもの」です。
これだけで「悪いクエリ」を特定することはできません。このビューで異常を見つけたら、次は `pg_stat_statements` で具体的なクエリを特定し、`EXPLAIN` で実行計画を見る……というふうに、「広い視野から狭い視野へ」と絞り込んでいくのが、トラブル解決の王道です。

DBの数字と対話できるようになると、運用はグッと楽になります。ぜひ、今の現場のDBの数値を一度眺めてみてください。普段見慣れない数値があったら、それが「改善の種」かもしれませんよ。

それでは、良いチューニングライフを!

コメント

タイトルとURLをコピーしました