4. PostgreSQL内置统计视图

PostgreSQL 的统计信息体系是生产监控的第一手数据来源。它不像外部监控那样需要额外采集器,而是由数据库进程在运行过程中持续写入共享内存,再通过一组以 pg_stat_ 开头的系统视图暴露出来。理解这些视图的字段含义、更新时机和相互关联,是搭建监控与容量规划体系的基础。本节聚焦四个最核心的视图:pg_stat_activity、pg_stat_database、pg_stat_bgwriter 和 pg_stat_replication,并给出可直接执行的实时查询。

一、统计信息的产生与刷新机制

PostgreSQL 的统计收集器(statistics collector)是一个后台进程,负责汇总各后端进程上报的计数。大多数计数器是累积值(counter),只增不减,例如提交次数、磁盘块读取数;而 pg_stat_activity 中的状态字段则是当前瞬时快照。理解这一点非常关键:累积型字段必须做差值才能得到速率,直接看绝对值没有监控意义。

统计信息的刷新由参数 track_counts(默认 on)和 track_activities(默认 on)控制。统计收集器默认每 PGSTAT_STAT_INTERVAL(约 500ms)更新一次,因此视图中的数据存在亚秒级延迟,不适合做精确到毫秒的审计,但完全满足监控与容量分析需求。此外,pg_stat_reset() 可重置当前库的统计,pg_stat_reset_shared() 可重置 bgwriter、archiver 等共享统计,重置后差值计算会失真,需在监控系统中记录重置事件。

PostgreSQL 统计信息产生与视图映射 后端进程 backend / autovacuum 后台写进程 bgwriter / checkpointer WAL 发送进程 walsender 统计收集器 statistics collector 共享内存 · 约500ms刷新 track_counts / track_activities pg_stat_activity 瞬时快照 · 会话状态 pg_stat_database 累积计数 · 库级吞吐 pg_stat_bgwriter 累积计数 · 写放大 pg_stat_replication 实时状态 · 复制延迟 关键提醒: 累积型字段(xact_commit、blks_read、buffers_clean 等)必须做时间差值才能得到速率;pg_stat_reset() 会清零计数,监控系统需记录重置事件。

二、pg_stat_activity:会话与等待事件

pg_stat_activity 是排障时最先查看的视图。它每个连接一行,核心字段包括:datname(数据库名)、pid(进程号)、usename、application_name、client_addr、state(会话状态)、wait_event_type 与 wait_event(等待事件)、query_start、state_change、backend_start 以及 query(当前或最近一条 SQL)。

state 的取值需要重点区分:active 表示正在执行;idle 表示空闲但未在事务中;idle in transaction 表示开启了事务却长时间不提交,这是最危险的连接泄漏信号;idle in transaction (aborted) 表示事务中已出错但未回滚。生产环境应重点监控后两者。

等待事件是定位性能瓶颈的钥匙。wait_event_type 常见值有 LWLock、Lock、IO、Client、BufferPin 等。例如大量会话处于 Lock 类型、transactionid 事件,说明存在行锁或表锁争用;处于 IO 类型、DataFileRead 事件,则说明磁盘读取成为瓶颈。

下面这条查询用于找出运行超过 5 分钟的活动会话,并按持续时间排序,是慢查询巡检的常用手段:

SELECT pid,
       now() - query_start AS duration,
       state,
       wait_event_type,
       wait_event,
       client_addr,
       left(query, 80) AS query_snippet
FROM pg_stat_activity
WHERE state = 'active'
  AND query_start < now() - interval '5 minutes'
  AND pid <> pg_backend_pid()
ORDER BY duration DESC;

排查 idle in transaction 泄漏时,可把条件换成 state LIKE 'idle in transaction%',并关注 state_change 距今的时长。若确认是应用未提交事务,可通过 pg_terminate_backend(pid) 终止,但需谨慎评估业务影响。

三、pg_stat_database:库级吞吐与命中率

pg_stat_database 每个数据库一行,是容量规划中计算 QPS、TPS 和缓存命中率的主要来源。关键字段:xact_commit(成功提交数)、xact_rollback(回滚数)、blks_read(磁盘块读取)、blks_hit(共享缓冲区命中)、tup_returned、tup_fetched、tup_inserted、tup_updated、tup_deleted、deadlocks、temp_files 与 temp_bytes。

缓存命中率公式为 blks_hit / (blks_hit + blks_read)。生产库通常应保持在 99% 以上;若持续低于 95%,说明 shared_buffers 偏小或存在大量全表扫描。temp_bytes 持续增长则意味着排序或哈希操作溢出到磁盘,需要检查 work_mem 与查询计划。

计算每秒事务数的查询(需间隔采样两次求差):

SELECT datname,
       xact_commit + xact_rollback AS total_xact,
       round(100.0 * blks_hit / nullif(blks_hit + blks_read, 0), 2) AS hit_ratio,
       temp_bytes,
       deadlocks
FROM pg_stat_database
WHERE datname IS NOT NULL
ORDER BY total_xact DESC;

实际监控中,应把该查询结果按固定间隔(如 15 秒)采集并保存,用相邻两次的差值除以时间间隔,得到真实的 TPS 与块读取速率。

四、pg_stat_bgwriter:写放大与检查点压力

pg_stat_bgwriter 只有一行,反映整个实例的写行为。核心字段:checkpoints_timed(按计划触发的检查点)、checkpoints_req(因 WAL 达到 max_wal_size 而强制触发的检查点)、buffers_checkpoint、buffers_clean、maxwritten_clean、buffers_backend、buffers_backend_fsync、buffers_alloc。

最重要的判断是 checkpoints_req 与 checkpoints_timed 的比例。如果 checkpoints_req 占比过高,说明检查点频繁被强制触发,通常因为 max_wal_size 太小或写入量突增,会导致 I/O 尖峰。另一个关键指标是 buffers_backend:它表示后端进程自己写脏页的次数。该值偏高说明 bgwriter 来不及清理,后端被迫参与写盘,会拖慢用户查询。理想情况下 buffers_backend 应远小于 buffers_clean + buffers_checkpoint。

SELECT checkpoints_timed,
       checkpoints_req,
       round(100.0 * checkpoints_req /
             nullif(checkpoints_timed + checkpoints_req, 0), 2) AS req_pct,
       buffers_checkpoint,
       buffers_clean,
       buffers_backend,
       maxwritten_clean
FROM pg_stat_bgwriter;

若 req_pct 超过 30%,建议调大 max_wal_size;若 buffers_backend 增长快,可适当提高 bgwriter_lru_maxpages 或 bgwriter_delay 的调优空间。

五、pg_stat_replication:复制延迟与同步状态

在主库上查询 pg_stat_replication,每个连接的备库一行。关键字段:pid(walsender 进程)、usename、application_name、client_addr、state(streaming、catchup、startup 等)、sent_lsn、write_lsn、flush_lsn、replay_lsn,以及 write_lag、flush_lag、replay_lag(PostgreSQL 10+ 提供的时间延迟)。

判断复制健康度,最直接的是比较 replay_lsn 与主库当前 pg_current_wal_lsn() 的差距,或直接看 replay_lag。若 state 长期停留在 catchup,说明备库追不上主库;若 replay_lag 持续增大,需检查备库 I/O 或网络带宽。

SELECT application_name,
       client_addr,
       state,
       sent_lsn,
       replay_lsn,
       pg_wal_lsn_diff(sent_lsn, replay_lsn) AS replay_delay_bytes,
       replay_lag
FROM pg_stat_replication;

replay_delay_bytes 以字节为单位量化了主备差距,比单纯看 LSN 更直观。对于同步复制场景,还需关注 sync_state 字段(sync、async、potential),确认同步备库是否真正在同步。

四个视图各有分工:pg_stat_activity 看“现在谁在干什么”,pg_stat_database 看“每个库吞吐多少”,pg_stat_bgwriter 看“写盘压力大不大”,pg_stat_replication 看“备库跟得上吗”。建议将它们纳入同一套采集脚本,按固定周期落库,再用差值计算速率,才能形成可用的监控基线。
直接在生产库高频查询 pg_stat_activity 时,注意 query 字段可能包含敏感信息;同时避免在业务高峰期执行全量排序查询。统计视图本身开销很小,但频繁调用 pg_stat_reset() 会破坏监控连续性,应严格限制权限。