pg_profile 用来采集 PostgreSQL 的统计快照,并生成 HTML 性能报告。它适合做日常巡检、问题复盘、上线前后对比和长期趋势分析。支持版本
PostgreSQL 版本 | 最早支持版本 | 插件版本 |
PostgreSQL 18 | v18.6_r1.15 | pg_profile 4.10 |
说明:
本文适用于云数据库 PostgreSQL 18集成版本。
插件简介
PostgreSQL 的很多统计视图是累计值,只能反映从上次 reset 到现在的总量。
pg_profile 的做法是定期采样,把统计结果保存到本地历史仓库。生成报告时,它计算两个 sample 之间的差值。常见用途:
生成某个时间段的 SQL 和数据库性能报告;
对比上线前后性能变化;
保存基线,用于以后对照;
采集多个 PostgreSQL 实例的数据;
结合
pg_stat_kcache、pg_wait_sampling、pgsentinel 展示 CPU、IO、等待事件和 ASH 信息。pg_profile 本身不需要预加载。它依赖 dblink 作为采集通道。plpgsql 是 PostgreSQL 默认语言,目标库需要已安装。环境准备
推荐先安装的插件
CREATE EXTENSION pg_stat_statements;CREATE EXTENSION pg_stat_kcache;CREATE EXTENSION pg_wait_sampling;CREATE EXTENSION pgsentinel;
这些插件能让报告内容更完整。缺少其中某个插件时,对应章节会缺失,但
pg_profile 仍可工作。安装 pg_profile
dblink 通常需要管理员创建:CREATE EXTENSION dblink;
安装
pg_profile:CREATE SCHEMA profile;CREATE EXTENSION pg_profile SCHEMA profile;
说明:
pg_profile 不可迁移,建议创建时就指定好 schema。后续不建议移动 schema。检查安装
SELECT extname, extversionFROM pg_extensionWHERE extname = 'pg_profile';SELECT * FROM profile.show_servers();
默认会创建一个名为
local 的 server。基本使用
采集快照
SELECT profile.take_sample();
至少需要两个 sample 才能生成报告:
SELECT profile.take_sample();-- 等待一段时间,或者运行负载SELECT profile.take_sample();SELECT * FROM profile.show_samples();
生成报告
\\o /tmp/pg_profile_report.htmlSELECT profile.get_report('local', 1, 2);\\o
把
1、2 替换为实际 sample id。也可以按时间范围生成:
\\o /tmp/pg_profile_report.htmlSELECT profile.get_report('local', tstzrange('2026-09-01 10:00', '2026-09-01 11:00'));\\o
生成最近两个 sample 的报告:
\\o /tmp/pg_profile_latest.htmlSELECT profile.get_report_latest('local');\\o
生成差异报告
对比两个时间段:
\\o /tmp/pg_profile_diff.htmlSELECT profile.get_diffreport('local', 1, 2, 3, 4);\\o
这类报告适合看上线前后、参数调整前后、优化前后的变化。
切换报告语言
SELECT profile.get_report_locale();SELECT profile.set_report_locale('zh-CN');SELECT profile.set_report_locale('en');
内置语言为
en 和 zh-CN。定时采样
使用系统 cron
*/30 * * * * psql -U postgres -d postgres -c 'SELECT profile.take_sample()' >/dev/null 2>&1* * * * * psql -U postgres -d postgres -c 'SELECT profile.take_subsample()' >/dev/null 2>&1
使用 pg_cron
如果已安装
pg_cron:SELECT * FROM profile.create_jobs(sample_interval => interval '30 minutes',subsample_interval => interval '1 minute',ash_subsample_interval => interval '1 minute',stmt_subsample_interval => NULL);SELECT * FROM profile.drop_jobs();
未安装
pg_cron 时,函数会返回跳过信息,不影响手工采样或系统 cron。基线管理
基线用于长期保留某个 sample 区间。常见场景是上线前、压测前、优化前。
SELECT profile.create_baseline('local', 'before_change', 1, 2, 90);SELECT * FROM profile.show_baselines('local');
基于基线生成报告:
\\o /tmp/baseline_report.htmlSELECT profile.get_report('before_change');\\o
删除基线:
SELECT profile.drop_baseline('local', 'before_change');
多实例采集
pg_profile 可以在一个库中采集多个 PostgreSQL 实例。远端采集需要先配置连接白名单。INSERT INTO profile.server_connstr_allowlist(host) VALUES ('db2.example.com');SELECT profile.create_server('db2','host=db2.example.com port=5432 dbname=postgres user=profile_collector',true,30,'生产库 db2');SELECT * FROM profile.show_servers();SELECT profile.take_sample();
连接串安全要求:
不允许写
password=,密码放在 .pgpass。不允许 URI 形式,例如
postgresql://...。不允许
service=、hostaddr=。远端 host 必须先加入
server_connstr_allowlist。子采样
完整 sample 间隔通常较长。子采样适合抓长查询、长事务和空闲事务。
配置阈值:
SELECT profile.set_server_subsampling('local',true,interval '10 seconds',interval '1 minute',100000,interval '5 minutes');
执行子采样:
SELECT profile.take_subsample();
说明:
take_sample() 不会自动执行普通 take_subsample(),需要单独调度。SQL 增量采样
用于观察分钟级 SQL 调用趋势。默认关闭。
SELECT profile.set_server_stmt_subsampling('local', true);SELECT profile.take_stmt_subsample('local');
开启后,报告中会出现 Statement Subsamples 相关内容。
表和索引大小采集
大小采集可能有开销,建议放到低峰时间。
SELECT profile.set_server_size_sampling(server => 'local',window_start => '02:00'::timetz,window_duration => interval '2 hours',sample_interval => interval '1 day',collect_mode => 'schedule');
collect_mode 可取:值 | 说明 |
off | 不主动计算大小 |
on | 每次 sample 都计算 |
schedule | 只在指定时间窗口计算 |
导出和导入
导出历史数据:
\\copy (SELECT * FROM profile.export_data('local')) TO '/tmp/profile_export.csv' WITH (FORMAT csv)
对外共享时建议脱敏 SQL:
\\copy (SELECT * FROM profile.export_data(server_name => 'local', obfuscate_queries => true)) TO '/tmp/profile_export_obfuscated.csv' WITH (FORMAT csv)
导入到分析库:
CREATE TABLE import_stage (section_id bigint, row_data json);\\copy import_stage FROM '/tmp/profile_export.csv' WITH (FORMAT csv)SELECT profile.import_data('import_stage', 'imported_');
参数说明
参数 | 默认值 | 说明 |
pg_profile.topn | 20 | 报告中 TOP N 数量 |
pg_profile.max_sample_age | 7 | sample 保留天数 |
pg_profile.max_query_length | 20000 | 报告中 SQL 文本截断长度 |
pg_profile.statements_reset | off | 采样时是否 reset SQL 统计,生产环境建议保持关闭 |
pg_profile.track_sample_timings | off | 是否记录采样阶段耗时 |
pg_profile.relsize_collect_mode | off | 大小采集模式 |
pg_profile.subsample_enabled | on | 子采样开关 |
pg_profile.stmt_subsample_retention_hours | 168 | SQL 增量采样保留小时数 |
查看当前显式配置:
SELECT current_setting('pg_profile.topn', true),current_setting('pg_profile.max_sample_age', true),current_setting('pg_profile.statements_reset', true);
返回
NULL 表示没有显式设置,使用内置默认值。权限说明
操作 | 权限要求 |
执行采样 | pg_monitor |
生成完整报告 | pg_read_all_stats |
修改 server、连接串、采样策略 | 扩展 owner 或管理员 |
reset 统计 | 管理员 |
报告和历史仓库可能包含 SQL 文本、对象名和会话信息。对外导出时建议开启
obfuscate_queries。常见问题
Q1:创建
pg_profile 报 dblink 权限错误。A:先由管理员创建
dblink,再创建 pg_profile。CREATE EXTENSION dblink;CREATE SCHEMA profile;CREATE EXTENSION pg_profile SCHEMA profile;
Q2:报
language plpgsql does not exist。A:目标库缺少
plpgsql。由管理员执行:CREATE EXTENSION plpgsql;
然后再创建
pg_profile。Q3:
take_sample() 连接失败如何处理?A:检查
profile.show_servers() 中的连接串、目标库 pg_hba.conf、白名单和 .pgpass。连接串中不能写明文密码。Q4:报告为空如何处理?
A:报告需要两个 sample 之间的差值。先确认:
SELECT * FROM profile.show_samples();
如果不足两个 sample,再执行一次
take_sample()。Q5:报告为什么缺少 CPU、等待事件或 ASH 内容?
A:检查目标库是否安装了
pg_stat_kcache、pg_wait_sampling、pgsentinel。缺少插件时,报告对应章节会缺失。Q6:历史数据为什么变少?
A:可能超过保留期被清理。检查
pg_profile.max_sample_age 和 server 级保留配置。重要时间段建议创建 baseline。Q7:
take_sample() 为什么很慢?A:开启采样耗时记录:
ALTER SYSTEM SET pg_profile.track_sample_timings = on;SELECT pg_reload_conf();SELECT profile.take_sample();SELECT * FROM profile.v_sample_timings ORDER BY sample_id DESC, time_spent DESC LIMIT 20;
常见原因是大小采集、SQL 条目过多、多 server 串行或远端连接慢。
卸载
卸载前如需保留数据,先导出:
\\copy (SELECT * FROM profile.export_data('local')) TO '/tmp/profile_export.csv' WITH (FORMAT csv)DROP EXTENSION pg_profile;
如果不再使用
dblink,确认无其它依赖后再删除:DROP EXTENSION dblink;
说明:
DROP EXTENSION pg_profile 会删除本地历史仓库。