pg_wait_sampling 用来采样 PostgreSQL 进程的等待事件。它可以看到当前等待、最近一段时间的等待历史,以及累计等待画像。支持版本
PostgreSQL 版本 | 最早支持版本 | 插件版本 |
PostgreSQL 18 | v18.6_r1.15 | pg_wait_sampling 1.1 |
说明:
本文适用于云数据库 PostgreSQL 18集成版本。
插件简介
pg_stat_activity 只能看到当前这一刻的 wait_event。如果问题已经过去,现场就没有了。pg_wait_sampling 通过后台进程周期性采样等待事件,提供三类数据:视图 | 用途 |
pg_wait_sampling_current | 查看当前每个进程在等什么 |
pg_wait_sampling_history | 查看最近一段时间的等待时间线 |
pg_wait_sampling_profile | 查看累计等待画像 |
常见问题:
数据库慢,是 CPU 忙还是在等锁、等 IO。
某段时间内主要等待事件是什么。
某条 SQL 是否经常等待锁或 IO。
环境准备
配置预加载
pg_wait_sampling 需要共享内存和后台进程,必须预加载。建议同时加载 pg_stat_statements。shared_preload_libraries = 'pg_stat_statements,pg_wait_sampling'pg_wait_sampling.history_size = 5000pg_wait_sampling.history_period = 10pg_wait_sampling.profile_period = 10pg_wait_sampling.profile_pid = onpg_wait_sampling.profile_queries = toppg_wait_sampling.profile_max_entries = 100000pg_wait_sampling.sample_cpu = on
修改后重启数据库:
pg_ctl -D $PGDATA restart
创建扩展
CREATE EXTENSION pg_stat_statements;CREATE EXTENSION pg_wait_sampling;
可以指定 schema:
CREATE SCHEMA pgws;CREATE EXTENSION pg_wait_sampling SCHEMA pgws;
授权
GRANT pg_monitor TO monitor_user;
普通用户没有
pg_monitor 时,只能看到自己的进程。常用查询
查看当前等待
SELECT c.pid, a.usename, a.state,coalesce(c.event_type, 'ON CPU') AS event_type,coalesce(c.event, 'ON CPU') AS event,substring(a.query, 1, 80) AS queryFROM pg_wait_sampling_current cLEFT JOIN pg_stat_activity a ON a.pid = c.pidORDER BY c.event_type NULLS LAST;
event_type 为空时表示进程没有等待事件,正在使用 CPU。查看累计等待画像
SELECT coalesce(event_type, 'ON CPU') AS event_type,coalesce(event, 'ON CPU') AS event,sum(count) AS samples,round(100.0 * sum(count) / sum(sum(count)) OVER (), 2) AS pctFROM pg_wait_sampling_profileGROUP BY 1, 2ORDER BY samples DESCLIMIT 15;
常见判断:
event_type | 说明 |
ON CPU | 进程没有等待,主要在用 CPU |
Lock | 锁等待 |
IO | IO 等待 |
LWLock | 内部轻量锁等待 |
Client | 等客户端读写 |
Timeout | 主动等待,例如 pg_sleep |
查看最近等待历史
SELECT ts, pid,coalesce(event_type, 'ON CPU') AS event_type,coalesce(event, 'ON CPU') AS event,queryidFROM pg_wait_sampling_historyWHERE ts > now() - interval '30 seconds'ORDER BY ts DESC, pidLIMIT 50;
history 是环形缓冲区,满了会覆盖旧数据。关联 SQL 文本
SELECT coalesce(p.event_type, 'ON CPU') AS event_type,coalesce(p.event, 'ON CPU') AS event,sum(p.count) AS samples,substring(s.query, 1, 80) AS queryFROM pg_wait_sampling_profile pLEFT JOIN pg_stat_statements s ON s.queryid = p.queryidWHERE p.queryid <> 0GROUP BY 1, 2, 4ORDER BY samples DESCLIMIT 15;
需要
pg_stat_statements 正常安装,并且 profile_queries 不为 none。建立一个观察窗口
SELECT pg_wait_sampling_reset_profile();-- 等待或运行负载SELECT pg_sleep(60);SELECT coalesce(event_type, 'ON CPU'), coalesce(event, 'ON CPU'), sum(count)FROM pg_wait_sampling_profileGROUP BY 1, 2ORDER BY 3 DESC;
pg_wait_sampling_reset_profile() 只能由管理员执行。函数和视图
对象 | 说明 |
pg_wait_sampling_get_current(pid int4) | 查看指定进程当前等待,传 NULL 返回全部 |
pg_wait_sampling_get_history() | 返回等待历史环形缓冲区 |
pg_wait_sampling_get_profile() | 返回累计等待画像 |
pg_wait_sampling_reset_profile() | 清空等待画像,仅管理员可执行 |
pg_wait_sampling_current | 当前等待视图 |
pg_wait_sampling_history | 等待历史视图 |
pg_wait_sampling_profile | 等待画像视图 |
参数说明
参数 | 默认值 | 生效方式 | 说明 |
pg_wait_sampling.history_size | 5000 | reload | history 环形缓冲区条数 |
pg_wait_sampling.history_period | 10 | reload | history 采样周期,单位毫秒 |
pg_wait_sampling.profile_period | 10 | reload | profile 采样周期,单位毫秒 |
pg_wait_sampling.profile_pid | on | reload | profile 是否按 PID 区分 |
pg_wait_sampling.profile_queries | top | reload | 是否记录 queryid,取值 none、top、all |
pg_wait_sampling.profile_max_entries | 100000 | reload | profile 最大条目数 |
pg_wait_sampling.sample_cpu | on | reload | 是否采样未等待进程 |
参数是
SIGHUP 级别,修改后执行:SELECT pg_reload_conf();
常见问题
Q1:查询时提示“必须预加载”怎么办?
A:把
pg_wait_sampling 加入 shared_preload_libraries,然后重启数据库。Q2:queryid 怎么都是0?
A:检查
pg_wait_sampling.profile_queries 是否为 none;检查是否安装并预加载 pg_stat_statements;检查 pg_stat_statements 是否排在 pg_wait_sampling 前面。Q3:pid 怎么都是0?
A:说明
pg_wait_sampling.profile_pid = off,所有进程合并统计。需要按进程看时改成 on。Q4:history 为什么只能回溯很短时间?
A:history 是环形缓冲区。可回溯时间受
history_size、活跃进程数和采样周期影响。可以增大 history_size 或增大 history_period。长期保留建议使用 pg_profile。Q5:普通用户只能看到自己的数据吗?
A:这是预期行为。需要全量数据时授予
pg_monitor。Q6:reset 报权限错误是怎么回事?
A:reset 是破坏性操作,只允许管理员执行。
卸载
DROP EXTENSION pg_wait_sampling;
然后从
shared_preload_libraries 中移除 pg_wait_sampling 并重启数据库。卸载或重启后,history 和 profile 中的内存数据都会丢失。