PostgreSQL自带的pg_stat_statements扩展一直是排查慢查询的主力工具,但它有几个明显的短板:统计数据是全局累计的,无法看到某个时间段内的查询表现;看不到查询的报错情况;也不知道查询来自哪个客户端IP。Percona开源的pg_stat_monitor扩展正是为了解决这些问题而设计的,它在pg_stat_statements的思路基础上做了大量增强,是PostgreSQL运维工具箱里非常值得一试的组件。

pg_stat_monitor的核心特性与工作原理
pg_stat_monitor本质上是一个PostgreSQL的extension,通过挂载共享内存中的统计数据结构,拦截数据库内核层的查询执行钩子来收集信息。每次查询执行完成后,相关信息会被归并到对应的bucket中。所谓bucket,是pg_stat_monitor引入的时间分桶机制:整个统计周期被划分为若干个固定长度的时间窗口,默认每分钟一个bucket,最多保留一定数量的bucket,超过后旧数据被清空,统计数据从零重新开始。
这个分桶机制带来一个质变:你可以回答“过去五分钟和上一个五分钟相比,查询耗时有没有恶化”这类问题,而pg_stat_statements只能告诉你自数据库启动以来的累计平均值。除了时间维度,pg_stat_monitor相比pg_stat_statements的主要增强还包括以下几点。
- 错误统计:记录每个查询语句的错误次数、错误码以及返回的样本错误消息,方便快速定位频繁报错的SQL。
- 客户端IP与主机名追踪:知道每条语句来自哪个应用服务器,多应用共用一个数据库时非常有用。
- 查询计划收集:配合pg_stat_monitor的plan功能可以查看语句的实际执行计划。
- 直方图统计:对调用耗时、CPU时间等提供桶状分布,直观看出耗时的长尾情况。
- 应用名与用户名维度:统计数据可以按application_name区分来源。
在资源消耗方面,pg_stat_monitor因为记录的维度更多,占用的共享内存会比pg_stat_statements大一些,但正常配置下开销依然可控。需要注意的是它要求统计信息存放在共享内存中,bucket数量和bucket时长需要在postgresql.conf中预先配置好,修改后需要重启数据库才能生效。
安装、配置与启用步骤
pg_stat_monitor需要从源码编译安装,官方仓库提供了针对不同PostgreSQL大版本的分支,编译前务必确认版本匹配。以Linux环境为例,先确保系统安装了PostgreSQL的开发头文件,然后执行标准的三步编译。
git clone https://github.com/percona/pg_stat_monitor.git cd pg_stat_monitor # PG_CONFIG指向你实际的pg_config路径 make PG_CONFIG=/usr/pgsql-15/bin/pg_config make PG_CONFIG=/usr/pgsql-15/bin/pg_config install
编译安装完成后,还需要修改postgresql.conf配置文件。pg_stat_monitor必须预加载到shared_preload_libraries中,这一点和pg_stat_statements一样,因为它需要在数据库启动时初始化共享内存结构。
# postgresql.conf shared_preload_libraries = 'pg_stat_monitor' pg_stat_monitor.pgsm_bucket_time = 60 # 每个bucket代表60秒 pg_stat_monitor.pgsm_max_buckets = 10 # 最多保留10个bucket pg_stat_monitor.pgsm_track_plans = on # 收集执行计划
配置保存后重启PostgreSQL服务,然后连接到目标数据库创建扩展即可。
CREATE EXTENSION pg_stat_monitor; -- 查看视图是否可用 SELECT bucket_done, substr(query, 1, 40) AS query_text, calls, mean_exec_time FROM pg_stat_monitor ORDER BY mean_exec_time DESC LIMIT 10;
这里有两个参数值得留意。pgsm_bucket_time决定单个时间窗口的粒度,粒度越小越能看到瞬时波动,但保留的历史也越短;pgsm_max_buckets决定保留多少个窗口。两者相乘就是可追溯的历史总时长,例如60秒乘以10个bucket就是最近十分钟的数据。生产环境中如果需要覆盖更长的时间跨度,可以适当调大bucket数量,但要注意内存占用会相应增长。
实战查询:定位慢查询与异常语句
安装完成后,pg_stat_monitor视图提供了几十个字段,常用的包括calls(调用次数)、mean_exec_time(平均执行耗时)、max_exec_time、total_exec_time、rows(返回或影响的行数)、client_ip、error_count等。排查慢查询最直接的方式就是按平均耗时或总耗时排序。
-- 找出当前bucket中平均耗时最高的10条语句
SELECT bucket_start_time,
userid::regrole,
substr(query, 1, 50) AS query_text,
calls,
round(mean_exec_time::numeric, 2) AS avg_ms,
round(max_exec_time::numeric, 2) AS max_ms,
client_ip
FROM pg_stat_monitor
ORDER BY mean_exec_time DESC
LIMIT 10;错误排查是pg_stat_monitor的一个亮点场景。假设应用频繁报错但日志分散,可以通过error_count字段快速锁定问题SQL,还能拿到实际的错误消息样本。
-- 查询报错次数最多的语句
SELECT substr(query, 1, 50) AS query_text,
calls,
error_count,
elevel,
substr(message, 1, 60) AS error_message
FROM pg_stat_monitor
WHERE error_count > 0
ORDER BY error_count DESC;做时间趋势分析时,可以利用bucket字段做分组聚合。比如比较最近几个时间窗口内某类查询的平均耗时变化,判断是否有性能劣化的趋势。此外还可以结合application_name字段,观察不同业务模块的数据库负载占比,这在多服务共用数据库的微服务架构下尤其有用。
-- 按时间桶观察查询耗时趋势
SELECT bucket,
date_trunc('minute', bucket_start_time) AS window_start,
calls,
round(mean_exec_time::numeric, 2) AS avg_ms
FROM pg_stat_monitor
WHERE query ILIKE '%orders%'
ORDER BY bucket DESC;与pg_stat_statements的对比及选型建议
两者的定位不同。pg_stat_statements胜在简单稳定,它是PostgreSQL官方contrib自带的扩展,几乎所有环境都能直接使用,累计统计的方式也符合容量规划类的分析需求。pg_stat_monitor则在可观测性维度上全面领先,时间分桶、错误追踪、IP归属、计划收集这些都是pg_stat_statements不具备的。
| 对比项 | pg_stat_statements | pg_stat_monitor |
|---|---|---|
| 统计方式 | 全局累计 | 时间bucket滚动 |
| 错误统计 | 不支持 | 支持,含错误码和消息样本 |
| 客户端IP | 不支持 | 支持 |
| 执行计划 | 不支持 | 支持收集 |
| 安装方式 | 官方自带 | 需源码编译 |
选型上给出几点建议。如果你的场景是常规的慢查询治理,pg_stat_statements加上定期的日志分析已经够用,没必要引入额外复杂度。但如果你需要近实时的性能监控、错误SQL的快速定位、按时间维度观察趋势,或者正在搭建数据库监控平台,那么pg_stat_monitor提供的丰富维度能显著提升排障效率。它也可以和pg_stat_statements共存于同一个实例,两者各自独立统计,互不干扰,可以先小范围试用再决定是否全面铺开。无论选择哪种方案,都建议配合定期采集落表的外部脚本,把监控数据持久化下来,避免bucket滚动或重启后历史统计丢失,这样才能支撑更长时间跨度的性能回溯分析。
pg_stat_monitorPostgreSQL监控数据库性能优化修改时间:2026-09-12 10:54:40