轻云听书app
17.87MB · 2025-10-15
pg_stat_statements
是PostgreSQL官方提供的核心性能监控模块,用于跟踪所有SQL语句的计划与执行统计信息。它能帮你回答:
简单来说,它是PostgreSQL性能优化的“黑匣子”——记录所有SQL的运行痕迹,帮你定位瓶颈。
pg_stat_statements
需要预加载(因为它需要共享内存),安装步骤分3步:
编辑postgresql.conf
(通常在/var/lib/postgresql/17/main/
或$PGDATA
目录):
# 1. 预加载模块(必须)
shared_preload_libraries = 'pg_stat_statements'
# 2. 启用查询ID计算(必须,用于唯一标识相同结构的查询)
compute_query_id = on
# 3. 可选配置(根据需求调整)
pg_stat_statements.max = 10000 # 最多跟踪10000条不同的SQL
pg_stat_statements.track = all # 跟踪顶级+嵌套语句(比如函数内的SQL)
pg_stat_statements.track_utility = on # 跟踪工具命令(如CREATE TABLE)
修改配置后需要重启数据库使生效:
sudo systemctl restart postgresql
登录数据库(如psql -U postgres
),执行以下命令启用扩展:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
参数 | 作用 | 默认值 |
---|---|---|
pg_stat_statements.max | 最多跟踪多少条不同的SQL(超过则丢弃最不常用的条目) | 5000 |
pg_stat_statements.track | 跟踪范围:top (仅顶级语句)、all (顶级+嵌套)、none (不跟踪) | top |
pg_stat_statements.track_utility | 是否跟踪工具命令(如VACUUM 、CREATE ) | on |
pg_stat_statements.track_planning | 是否跟踪计划时间(会增加性能开销) | off |
pg_stat_statements.save | 重启后是否保留统计信息 | on |
pg_stat_statements
提供两个核心视图:
pg_stat_statements
:SQL统计详情这个视图是性能分析的核心,每一行对应一条不同结构的SQL(用queryid
标识)。关键字段如下:
字段 | 含义 |
---|---|
queryid | SQL的唯一哈希ID(相同结构的SQL哈希值相同) |
query | SQL文本(常量会被替换为$1 、$2 ,比如SELECT * FROM users WHERE id = $1 ) |
calls | 执行次数 |
total_exec_time | 总执行时间(毫秒,最常用的慢查询指标) |
mean_exec_time | 平均执行时间(毫秒) |
rows | 总返回/影响的行数 |
shared_blks_hit | 共享缓存命中次数(越高越好,说明少读磁盘) |
shared_blks_read | 共享缓存未命中次数(需要读磁盘,IO开销大) |
stats_since | 统计开始时间 |
示例:计算缓存命中率(越高越好):
SELECT
query,
calls,
total_exec_time,
100.0 * shared_blks_hit / NULLIF(shared_blks_hit + shared_blks_read, 0) AS hit_percent
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 5;
pg_stat_statements_info
:模块自身统计这个视图只有1行,记录模块的运行状态:
字段 | 含义 |
---|---|
dealloc | 因超过pg_stat_statements.max 而丢弃的SQL条目数(值大说明max 太小) |
stats_reset | 统计信息最后重置时间 |
SELECT
query,
calls,
total_exec_time,
mean_exec_time,
rows
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 5;
结果解读:total_exec_time
最高的SQL是性能优化的优先目标(比如总时间10秒的SQL,即使平均时间短,但执行次数多也会拖慢整体性能)。
SELECT
query,
calls,
100.0 * shared_blks_hit / NULLIF(shared_blks_hit + shared_blks_read, 0) AS hit_percent
FROM pg_stat_statements
WHERE hit_percent < 90 -- 命中率低于90%
ORDER BY hit_percent ASC;
优化思路:命中率低说明SQL经常读磁盘,可能需要添加索引或加大shared_buffers
(数据库缓存)。
如果统计信息太旧(比如测试环境),可以重置:
-- 重置所有统计(仅超级用户可执行)
SELECT pg_stat_statements_reset();
-- 重置某条SQL的统计(需指定queryid)
SELECT pg_stat_statements_reset(0, 0, '1234567890'); -- 0表示不限制用户/数据库,queryid替换为实际值
pg_stat_statements
是基础,但有个明显局限——统计是累计的(比如某条SQL的总执行时间是从启动到现在的总和),无法看到时间维度的变化(比如“最近1小时这条SQL的执行时间是否变长?”)。
pg_stat_monitor
是Percona开发的增强版模块,解决了这个问题,适合持续监控。
pg_stat_statements
)特性 | pg_stat_statements | pg_stat_monitor |
---|---|---|
累计统计 | ||
按时间窗口统计 | (比如每1分钟一个窗口) | |
响应时间直方图 | (看SQL的响应时间分布) | |
慢查询日志集成 | (自动标记慢查询) | |
更多维度过滤(如用户、数据库) | (更细粒度) |
pg_stat_monitor
需要从Percona仓库安装(或编译源码):
# 安装Percona仓库(以Debian/Ubuntu为例)
sudo apt install percona-postgresql-17-pg_stat_monitor
修改postgresql.conf
:
shared_preload_libraries = 'pg_stat_monitor' # 替换或新增
pg_stat_monitor.interval = 60 # 时间窗口大小(秒,默认60)
pg_stat_monitor.max = 10000 # 最多跟踪10000条SQL
重启数据库后创建扩展:
CREATE EXTENSION IF NOT EXISTS pg_stat_monitor;
SELECT
query,
sum(calls) AS total_calls,
avg(mean_exec_time) AS avg_mean_exec_time,
time
FROM pg_stat_monitor
WHERE time >= NOW() - INTERVAL '1 hour'
GROUP BY query, time
ORDER BY avg_mean_exec_time DESC;
性能优化不是“一次性操作”,而是持续循环。结合pg_stat_statements
和pg_stat_monitor
,流程如下:
用pg_stat_statements
找总执行时间最长或缓存命中率最低的SQL;用pg_stat_monitor
看时间维度的性能变化(比如某条SQL的执行时间从10ms涨到100ms)。
对瓶颈SQL运行EXPLAIN ANALYZE
,看是否缺少索引、是否全表扫描:
EXPLAIN ANALYZE SELECT * FROM orders WHERE customer_id = 123;
结果解读:如果看到Seq Scan on orders
(全表扫描),说明缺少customer_id
的索引。
比如给orders
表的customer_id
添加索引:
CREATE INDEX idx_orders_customer_id ON orders(customer_id);
优化后,用pg_stat_statements
重新查询该SQL的total_exec_time
和shared_blks_read
,看是否下降;用pg_stat_monitor
看时间窗口内的执行时间是否恢复正常。
SELECT pg_stat_statements_reset();
),避免旧数据干扰分析。pg_stat_statements.max
:如果dealloc
值很大(看pg_stat_statements_info
),说明max
太小,需要增大(比如从5000改到10000)。track_planning
谨慎:track_planning
会跟踪计划时间,但会增加性能开销,仅在需要分析计划问题时开启。pg_stat_statements
的query
字段包含SQL文本,仅超级用户和pg_read_all_stats
角色能看其他用户的SQL(避免敏感信息泄露)。pg_stat_statements
找出最耗时的前3条SQL?答案:
SELECT query, calls, total_exec_time FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 3;
pg_stat_statements.track
设置为all
会跟踪哪些语句?答案:会跟踪顶级语句(如客户端直接执行的SQL)和嵌套语句(如函数或存储过程内的SQL)。
pg_stat_statements_info
中的dealloc
值很大,说明什么?答案:说明pg_stat_statements.max
设置太小,导致很多SQL条目被丢弃,需要增大max
值。
ERROR: could not access file "pg_stat_statements": No such file or directory
原因:没有安装pg_stat_statements
扩展,或没有预加载模块。
解决:
apt install postgresql-17-pg-stat-statements
)。shared_preload_libraries
为pg_stat_statements
并重启数据库。ERROR: permission denied for function pg_stat_statements_reset
原因:当前用户没有执行pg_stat_statements_reset
的权限。
解决:
postgres
)执行。GRANT EXECUTE ON FUNCTION pg_stat_statements_reset() TO your_user;
ERROR: pg_stat_statements must be loaded via shared_preload_libraries
原因:没有在postgresql.conf
中预加载pg_stat_statements
。
解决:修改shared_preload_libraries
并重启数据库。
pg_stat_statements
模块pg_stat_monitor
模块compute_query_id