PostgreSQL 监控与诊断体系:pg_stat_activity、慢查询、pg_stat_statements 与 Prometheus 告警

构建完整的 PostgreSQL 监控与诊断体系:pg_stat_database 与 pg_stat_activity 关键指标解读、慢查询日志与 log_min_duration_statement、auto_explain 自动执行计划、pg_stat_statements 语句级统计、Prometheus + postgres_exporter + Grafana 仪表盘搭建、核心告警规则(连接数/复制延迟/死元组)、诊断常用 SQL 与常见问题定位方法论。

数据库告警时,你希望第一反应是"打开仪表盘快速定位",而不是"登录服务器逐个猜"。一套完整的 PostgreSQL 监控体系,核心由三部分构成:系统视图(pg_stat_*)、日志与执行计划(慢查询/auto_explain)、外部指标采集(Prometheus/Grafana)。

核心认知:监控不是"收集数据",而是"压缩信息"。从 pg_stat_activity 的会话视图,到 pg_stat_statements 的语句级 Top N,再到 Prometheus 的长期指标,层级越高,越接近"能直接定位根因"。


一、监控体系概览

1.1 三层监控架构

监控体系分三层:应用层(连接池/PgBouncer、错误率、响应延迟)、数据库层(pg_stat_* 视图、日志、SQL 统计)、采集层(postgres_exporter → Prometheus → Grafana/Alertmanager)。

1.2 关键监控对象清单

对象核心指标数据来源
会话连接数、state、wait_eventpg_stat_activity
数据库事务、命中率、死锁pg_stat_database
语句Top N、执行时间、缓冲区pg_stat_statements
表扫描方式、死元组pg_stat_user_tables
复制延迟、槽位pg_stat_replication / pg_stat_subscription
资源CPU、内存、磁盘、IO操作系统层

二、pg_stat_database 关键指标

2.1 核心字段

SELECT * FROM pg_stat_database WHERE datname = current_database();
字段含义健康参考
numbackends当前连接数低于 max_connections 的 80%
xact_commit已提交事务数持续增长
xact_rollback回滚事务数比例应低
blks_read从磁盘读的块数命中率高
blks_hit缓存命中的块数命中率 > 99%
deadlocks死锁次数趋近 0
temp_files临时文件数频繁出现说明 work_mem 不足
temp_bytes临时文件字节过大说明排序/哈希溢出到磁盘

2.2 缓存命中率计算

SELECT
  datname,
  round(100.0 * blks_hit / GREATEST(blks_hit + blks_read, 1), 2) AS cache_hit_ratio
FROM pg_stat_database;
-- 命中率低于 99% 通常说明 shared_buffers 偏小或全表扫描过多

2.3 回滚率与临时文件

-- 高回滚率往往是应用层异常/事务冲突
SELECT datname,
       xact_commit, xact_rollback,
       round(100.0 * xact_rollback / GREATEST(xact_commit + xact_rollback, 1), 2) AS rollback_pct,
       temp_files, pg_size_pretty(temp_bytes) AS temp_used
FROM pg_stat_database
WHERE datname NOT IN ('postgres', 'template0', 'template1')
ORDER BY rollback_pct DESC;

提示:temp_files 频繁增长说明 work_mem 设置过小,排序/哈希被写到磁盘,性能会大幅下降。


三、pg_stat_activity 会话分析

3.1 会话状态与等待事件

SELECT pid, usename, datname, state,
       wait_event_type, wait_event,
       query_start, xact_start,
       left(query, 60) AS query
FROM pg_stat_activity
WHERE datname IS NOT NULL
ORDER BY query_start;

state 取值:active(正在执行)、idle(空闲)、idle in transaction(事务内空闲,高危)、idle in transaction (aborted)(事务已中断未回滚)。

3.2 等待事件定位

PostgreSQL 9.6+ 提供 wait_event_type / wait_event,精准描述进程在等什么:

wait_event_type常见事件含义
Locktransactionid / relation等锁
IODataFileRead / WALWrite磁盘 IO 瓶颈
ActivityAutoVacuumMain后台进程活动
ClientClientRead等待应用发来数据
Extension自定义扩展等待扩展锁/IO
-- 按等待事件聚合,定位系统瓶颈
SELECT wait_event_type, wait_event, count(*)
FROM pg_stat_activity
WHERE state = 'active'
GROUP BY wait_event_type, wait_event
ORDER BY count(*) DESC;

3.3 常见会话诊断 SQL

-- 1. 找出运行最久的查询
SELECT pid, now() - query_start AS dur,
       state, wait_event_type, wait_event,
       query
FROM pg_stat_activity
WHERE state = 'active' AND query_start IS NOT NULL
ORDER BY query_start ASC LIMIT 20;

-- 2. 找出 idle in transaction(见事务专题)
SELECT pid, state, now() - state_change AS idle_for,
       left(query, 50) AS query
FROM pg_stat_activity
WHERE state LIKE 'idle in transaction%'
ORDER BY state_change ASC;

四、慢查询日志与 auto_explain

4.1 log_min_duration_statement

-- 记录执行超过 1 秒的所有语句
ALTER SYSTEM SET log_min_duration_statement = '1000ms';
ALTER SYSTEM SET log_destination = 'stderr';
SELECT pg_reload_conf();

日志输出示例:

2026-09-27 10:00:01 UTC [12345] LOG:  duration: 2345.123 ms  statement: SELECT * FROM orders WHERE user_id = 1001 ORDER BY created_at DESC

4.2 慢查询日志分析

慢查询日志可配合 grep/awk 提取 duration: 行并按耗时排序,快速得到 Top N。更系统的语句级分析仍推荐 pg_stat_statements(见第五章)。

4.3 auto_explain:自动记录执行计划

auto_explain 能在慢查询触发时自动把 EXPLAIN 计划写进日志,免去"复现慢查询"的痛苦:

-- 需在共享库中加载(改后重启)
ALTER SYSTEM SET shared_preload_libraries = 'auto_explain';
ALTER SYSTEM SET auto_explain.log_min_duration = '1000ms';
ALTER SYSTEM SET auto_explain.log_analyze = 'on';
ALTER SYSTEM SET auto_explain.log_buffers = 'on';
ALTER SYSTEM SET auto_explain.log_nested_statements = 'on';
-- 重启后生效

4.4 会话级开启(无需重启)

-- 当前会话手动开启(调试时非常有用)
LOAD 'auto_explain';
SET auto_explain.log_min_duration = '100ms';
SET auto_explain.log_analyze = 'on';
-- 之后执行的慢查询会自动输出执行计划到日志
auto_explain 参数默认说明
log_min_duration-1(关闭)超过该毫秒数记录计划
log_analyzeoff使用 EXPLAIN ANALYZE
log_buffersoff记录 buffer 使用
log_nested_statementsoff记录嵌套语句
log_formattext可设 json 便于采集

五、pg_stat_statements 语句级统计

5.1 启用 pg_stat_statements

-- 需重启生效
ALTER SYSTEM SET shared_preload_libraries = 'pg_stat_statements';
ALTER SYSTEM SET pg_stat_statements.max = 5000;
ALTER SYSTEM SET pg_stat_statements.track = 'top';
-- 重启后
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

5.2 Top 慢语句分析

-- 按总耗时排序的 Top 语句
SELECT
  round(total_exec_time::numeric, 2) AS total_ms,
  round(mean_exec_time::numeric, 2) AS avg_ms,
  calls,
  rows,
  round(100.0 * shared_blks_hit /
        GREATEST(shared_blks_hit + shared_blks_read, 1), 2) AS hit_ratio,
  left(query, 80) AS query
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 20;

5.3 按平均耗时与调用次数

-- 平均耗时最长的 Top 10
SELECT round(mean_exec_time::numeric,2) AS avg_ms,
       calls, rows,
       left(query, 80) AS query
FROM pg_stat_statements
ORDER BY mean_exec_time DESC LIMIT 10;

-- 调用次数最多(可能是热点语句)
SELECT calls, round(total_exec_time::numeric,2) AS total_ms,
       round(mean_exec_time::numeric,2) AS avg_ms,
       left(query, 80) AS query
FROM pg_stat_statements
ORDER BY calls DESC LIMIT 10;

5.4 关键字段速查

字段含义
calls执行次数
total_exec_time总耗时(PG13+;旧版 total_time)
mean_exec_time平均耗时
rows返回行数总和
shared_blks_hit / shared_blks_read缓存命中/读盘块数
temp_bytes临时文件字节
blk_read_time / blk_write_timeIO 等待时间

建议:pg_stat_statements 是慢查询治理的主入口——先看 Top 总耗时,再下钻到 EXPLAIN,比翻日志高效得多。必要时 SELECT pg_stat_statements_reset(); 重置统计窗口。


六、Prometheus 与 postgres_exporter

6.1 postgres_exporter 部署

postgres_exporter 是一个 Go 编写的独立采集器,把 PostgreSQL 指标暴露成 Prometheus 格式:

# docker-compose 片段
services:
  postgres_exporter:
    image: prometheuscommunity/postgres-exporter:latest
    environment:
      DATA_SOURCE_NAME: "postgresql://monitor:secret@postgres:5432/postgres?sslmode=disable"
    ports:
      - "9187:9187"
    depends_on: [postgres]

6.2 Prometheus 抓取配置

# prometheus.yml 片段
scrape_configs:
  - job_name: postgres
    static_configs:
      - targets: ["postgres_exporter:9187"]

6.3 常用指标

指标含义
pg_stat_database_numbackends数据库连接数
pg_stat_database_xact_commit_total提交事务数
pg_stat_database_deadlocks_total死锁计数
pg_stat_database_blks_hit / blks_read缓存命中
pg_stat_activity_idle_in_transaction_seconds长事务时长
pg_stat_user_tables_n_dead_tup死元组数
pg_replication_lag复制延迟字节

6.4 采集注意事项

□ 创建最小权限监控角色(见下方 SQL)
□ 设置 scrape 间隔与 postgres_exporter 查询频率匹配
□ 监控大库时限制 pg_stat_statements 查询的采样
□ 为指标设置 retention 与 downsampling
-- 最小权限监控账号
CREATE ROLE monitor LOGIN PASSWORD 'secret';
GRANT CONNECT ON DATABASE mydb TO monitor;
GRANT pg_monitor TO monitor;  -- PG 10+ 内置监控角色

七、Grafana 仪表盘与告警

7.1 推荐仪表盘

社区成熟的 PostgreSQL 仪表盘(Grafana 官方 / postgres_exporter 自带面板)通常包含:

面板展示内容
连接数与状态连接总数、state 分布
事务吞吐commit/rollback 速率
缓存命中率全局与按库
锁等待与死锁等锁会话数、死锁计数
复制状态延迟、槽位 WAL 保留
Top 慢语句pg_stat_statements 前 N

7.2 核心告警规则

# Prometheus 告警规则(postgres_alerts.yml)
groups:
  - name: postgres-critical
    rules:
      - alert: PostgresDown
        expr: pg_up == 0
        for: 1m
        labels: { severity: critical }

      - alert: ConnectionSaturation
        expr: pg_stat_database_numbackends > (pg_settings_max_connections * 0.8)
        for: 5m
        labels: { severity: warning }

      - alert: DeadTupleHigh
        expr: pg_stat_user_tables_n_dead_tup > 10000
        for: 10m
        labels: { severity: warning }

      - alert: ReplicationLag
        expr: pg_replication_lag > 104857600   # 100MB
        for: 5m
        labels: { severity: critical }

      - alert: IdleInTransaction
        expr: pg_stat_activity_idle_in_transaction_seconds > 300
        for: 2m
        labels: { severity: warning }

      - alert: CacheHitLow
        expr: pg_stat_database_blks_hit /
              (pg_stat_database_blks_hit + pg_stat_database_blks_read) < 0.99
        for: 15m
        labels: { severity: warning }

7.3 告警分级建议

  • critical(立即告警):实例宕机、复制中断
  • high(分钟级):连接打满、复制延迟持续增长
  • warning(观察排查):死元组堆积、命中率下降、长事务
  • info(记录趋势):临时文件增长、回滚率升高

八、诊断常用 SQL 与问题定位

8.1 一键健康体检

-- 数据库级体检
SELECT
  d.datname,
  d.numbackends,
  round(100.0 * d.blks_hit / GREATEST(d.blks_hit + d.blks_read, 1), 2) AS hit_ratio,
  d.deadlocks,
  d.temp_files,
  pg_size_pretty(pg_database_size(d.datname)) AS db_size
FROM pg_stat_database d
WHERE d.datname NOT IN ('postgres', 'template0', 'template1')
ORDER BY pg_database_size(d.datname) DESC;

8.2 常见问题定位方法论

现象 "数据库变慢"
  ├─ 1. pg_stat_activity:是否有长查询/长事务/锁等待
  ├─ 2. pg_stat_statements:Top 语句是否耗时长/调用多
  ├─ 3. EXPLAIN (ANALYZE, BUFFERS):计划是否合理、是否全表扫描
  ├─ 4. 资源层:CPU/IO/网络是否饱和
  ├─ 5. 缓存:命中率是否下降、shared_buffers 是否不足
  └─ 6. 表健康:死元组/膨胀是否需要 VACUUM/REINDEX

8.3 连接打满排查

-- 连接打满时:找出占用连接的应用
SELECT usename, application_name, count(*)
FROM pg_stat_activity
GROUP BY usename, application_name
ORDER BY count(*) DESC;

-- 清理空闲连接(谨慎)
SELECT pg_terminate_backend(pid) FROM pg_stat_activity
WHERE state = 'idle' AND now() - state_change > INTERVAL '10 minutes';

8.4 IO 与 WAL 诊断

-- 检查 WAL 写入与检查点
SELECT checkpoints_timed, checkpoints_req,
       checkpoint_write_time, checkpoint_sync_time,
       wal_bytes
FROM pg_stat_bgwriter;

-- 查看每个数据库的 IO
SELECT datname, blk_read_time, blk_write_time
FROM pg_stat_database
WHERE datname NOT IN ('postgres', 'template0', 'template1');

8.5 长期趋势指标清单

  • 性能:事务速率、命中率、平均执行时间(30s~1min)
  • 容量:库大小、表大小、WAL 增长(1min)
  • 健康:死元组、膨胀率、复制延迟(1min)
  • 稳定性:死锁、回滚率、连接数(1min)
  • 安全:登录失败、审计事件(实时)

常见问题(FAQ)

pg_stat_statements 和慢查询日志有什么区别?

log_min_duration_statement 记录单次超阈值语句(含完整 SQL);pg_stat_statements 是聚合统计(按规范化 SQL 汇总调用次数、平均耗时),更适合找 Top 热点。两者配合:用 pg_stat_statements 找 Top,用 auto_explain/日志看单条计划的细节。

auto_explain 会影响性能吗?

会,但可控。只对超过阈值的慢语句记录计划,且 log_analyze 会真正执行分析,大库阈值建议 1~2 秒以上;调试期临时调小,生产保持谨慎。

死元组告警阈值设多少合适?

通用经验:n_dead_tup 超过 10000 或占活元组比例超过 10%~20% 就应关注。结合 last_autovacuum 看:死元组持续增长且 Autovacuum 长时间没跑,说明回收被阻塞(常见长事务),这才是告警的深意。

连接打满如何处理?

先按 application_name 分组找出连接占用来源,确认连接池是否过小或应用泄漏。临时处置可 pg_terminate_backend 清理空闲连接;根本解决是规划 max_connections、上 PgBouncer 连接池、给应用设超时。

监控账号需要多大权限?

用最小权限:CREATE ROLE monitor LOGIN + GRANT pg_monitor TO monitor(PG 10+ 内置角色,可读所有统计视图)。不要给监控账号超级用户权限;postgres_exporter 用它抓取即够。


相关阅读

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「database」更多文章

  1. 数据库安全加固与审计实战:权限最小化、加密、脱敏与合规
  2. 数据库容量规划与资源治理:从评估、监控到扩展路径
  3. 数据库字符集、排序规则与乱码实战:utf8mb4、Collation 选择与排查