【テクニカル・上級編】 pg_stat_activity – PostgreSQL

PostgreSQLの心拍を感じる:`pg_stat_activity`を使いこなすための深層解剖

PostgreSQLを長年運用していると、深夜の呼び出しや原因不明のパフォーマンス低下といった「修羅場」に何度か遭遇するはずです。そんな時、皆さんはまずどこを見ますか? 多くのエンジニアが迷わず叩くのが `pg_stat_activity` でしょう。

しかし、単に `SELECT FROM pg_stat_activity` を実行して「お、なんか重いクエリがあるな」と眺めるだけで終わらせてはいないでしょうか。このビューは、PostgreSQLという巨大なエンジンの「今」を映し出す鏡です。今日は、この鏡の解像度を一段階上げ、トラブルシューティングの現場でどう武器にするか、少し踏み込んだ話をしましょう。

—

1. 「待ち」の真実を読み解く:`wait_event_type` と `wait_event`

多くの人が `state` カラムの `active` や `idle` に注目しがちですが、本当に重要なのは `wait_event_type` です。ここには、PostgreSQLが今、何のために立ち止まっているのかが刻まれています。

例えば、`Lock` というイベントタイプが見えた時。これは単に「ロック待ち」と片付けるのではなく、どの種類のロックかを推測する必要があります。`tuple` ロックなのか、`relation` ロックなのか。あるいは、`LWLock`(Lightweight Lock)であれば、それはデータの内容そのものより、`WALWriteLock` のような内部構造の競合かもしれません。

特に、`IO` 関連のイベントが頻発している場合、それはクエリの書き方が悪いのではなく、ディスクI/Oのボトルネックか、あるいは共有バッファのフラッシュタイミングの問題である可能性が高い。この「クエリ層」と「物理層」の切り分けができるようになると、無駄な `EXPLAIN` 解析に時間を費やすことがなくなります。

2. 見えないクエリを追う:`query_start` と `backend_start` の罠

パフォーマンスチューニングで意外と落とし穴になるのが、`query_start` の値です。

皆さんも経験があるかもしれませんが、アプリケーション側で「タイムアウトした」というログが出ているのに、DB上ではクエリが走り続けているように見えるケース。ここで `pg_stat_activity` を見ると、`query_start` が古いまま更新されていないことがあります。

これは、PostgreSQLのバックエンドプロセスがクエリを実行中であり、かつそれが `active` な状態にあることを示していますが、もしその時間が極端に長い場合、それはクエリの実行速度の問題ではなく、クライアントとのネットワーク帯域の問題や、クライアント側で結果セットのフェッチが詰まっている(idle in transaction状態の引き金)可能性を疑うべきです。

3. ロック待ちの連鎖を断つ

トラブル対応の際、`pg_blocking_pids(pid)` を組み合わせて、ロックの「源流」を探すのは基本中の基本です。しかし、さらに一歩進んで、以下のようなクエリを自分のツールボックスに入れておくことをお勧めします。

SELECT
pid,
usename,
state,
wait_event_type,
query,
age(clock_timestamp(), query_start) as duration
FROM pg_stat_activity
WHERE state != ‘idle’
AND (wait_event_type IS NOT NULL OR state = ‘active’)
ORDER BY duration DESC;

このクエリを眺めていると、時折「なぜここでロックが発生しているのか?」という不可解な現象にぶつかります。その時、PostgreSQLの内部では、`AccessExclusiveLock` を必要とするDDLが、裏で走っている長い読み取りクエリと干渉していることが多い。

4. 最後に:監視と「直感」のバランス

`pg_stat_activity` は、あくまで「スナップショット」です。1秒前の瞬間を切り取ったに過ぎません。長時間実行されるクエリは見つけやすいですが、数ミリ秒で終わるクエリが大量に積み重なって発生する「マイクロバースト」のような現象は、このビューを眺めているだけでは見抜けないこともあります。

そんな時は、`pg_stat_statements` と組み合わせて、「どのクエリがトータルで最も負荷をかけているのか」を統計的に俯瞰し、その上で `pg_stat_activity` を使って「今、誰がその爆弾を投げているのか」を特定する。この二段構えこそが、熟練のエンジニアが取るべきアプローチです。

PostgreSQLは非常に素直なデータベースです。統計情報やビューに吐き出される値には、必ず「なぜそうなったか」の理由が隠されています。もし今、皆さんのDBで謎の負荷が発生しているなら、まずは `pg_stat_activity` に「何をしているの?」と問いかけてみてください。きっと、彼らは雄弁に語ってくれるはずです。

それでは、また次回の記事でお会いしましょう。良いチューニングライフを。

コメント

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