一、支持版本
| PostgreSQL 版本 | 最早支持版本 | 插件版本 |
| PostgreSQL 18 | v18.6_r1.15 | pg_stat_kcache 2.3.1 |
注意:说明:
注意:这篇适用于云数据库 PostgreSQL 18集成版本。
二、插件简介
pg_stat_statements 能看到 SQL 调用次数、耗时和 buffer 统计,但不能说明一条 SQL 到底消耗了多少 CPU,也不能说明是否真的发生了物理磁盘读写。
pg_stat_kcache 补上这部分信息。常见用途:
| 问题 | 查看指标 |
| 哪条 SQL 最耗 CPU | exec_user_time、exec_system_time |
| 哪条 SQL 有真实物理读写 | exec_reads、exec_writes |
| 是否有缺页 | exec_minflts、exec_majflts |
| 是否有明显调度争抢 | exec_nvcsws、exec_nivcsws |
注意:shared_blks_read 不是物理读,它表示 PostgreSQL shared buffers 未命中。数据可能仍在 OS Page Cache 中。exec_reads 才是文件系统层面的读取字节数。
四、配置预加载
pg_stat_kcache 需要共享内存,必须预加载。pg_stat_statements 要放在它前面。
shared_preload_libraries = 'pg_stat_statements,pg_stat_kcache'pg_stat_statements.track = allpg_stat_kcache.track = toppg_stat_kcache.track_planning = off
修改后重启数据库:
pg_ctl -D $PGDATA restart
五、创建扩展
CREATE EXTENSION pg_stat_statements;CREATE EXTENSION pg_stat_kcache;
可以指定 schema:
CREATE SCHEMA pgsk;CREATE EXTENSION pg_stat_kcache SCHEMA pgsk;
六、授权
监控账号需要读取全量数据时,授予:
GRANT pg_monitor TO monitor_user;
普通用户没有 pg_monitor 时,只能看到自己的统计。
八、查看最耗 CPU 的 SQL
SELECT substring(query, 1, 80) AS query, round((exec_user_time + exec_system_time)::numeric, 3) AS cpu_sec, round(exec_user_time::numeric, 3) AS user_sec, round(exec_system_time::numeric, 3) AS system_sec, rolname, datnameFROM pg_stat_kcache_detailWHERE top IS TRUEORDER BY exec_user_time + exec_system_time DESCLIMIT 10;
user_sec 高通常表示计算多,例如排序、聚合、表达式计算。system_sec 高通常表示系统调用多,例如大量小 IO 或临时文件操作。
九、查看真实物理读写最多的 SQL
SELECT substring(query, 1, 80) AS query, pg_size_pretty(exec_reads) AS phys_read, pg_size_pretty(exec_writes) AS phys_write, exec_reads_blks, exec_writes_blksFROM pg_stat_kcache_detailWHERE top IS TRUE AND exec_reads > 0ORDER BY exec_reads DESCLIMIT 10;
十、对比 shared buffer 未命中和真实物理读
SELECT substring(s.query, 1, 80) AS query, s.shared_blks_read AS shared_miss_blocks, pg_size_pretty(k.exec_reads) AS physical_readFROM pg_stat_kcache() kJOIN pg_stat_statements s ON s.queryid = k.queryid AND s.dbid = k.dbid AND s.userid = k.userid AND s.toplevel = k.topWHERE k.top IS TRUEORDER BY k.exec_reads DESCLIMIT 10;
如果 shared_blks_read 高但 exec_reads 低,说明很多数据命中了 OS Page Cache;如果两者都高,才更像真实磁盘 IO 压力。
十一、查看整库资源消耗
SELECT datname, round((exec_user_time + exec_system_time)::numeric, 2) AS cpu_sec, pg_size_pretty(exec_reads) AS phys_read, pg_size_pretty(exec_writes) AS phys_write, stats_sinceFROM pg_stat_kcacheORDER BY exec_user_time + exec_system_time DESC;
十二、查看缺页和上下文切换
SELECT substring(query, 1, 80) AS query, exec_minflts, exec_majflts, exec_nvcsws, exec_nivcswsFROM pg_stat_kcache_detailWHERE top IS TRUEORDER BY exec_majflts DESC, exec_nivcsws DESCLIMIT 10;
exec_majflts 持续较高时,要关注宿主机内存压力。exec_nivcsws 高时,要关注 CPU 争抢。
十三、函数和视图
| 对象 | 说明 |
| pg_stat_kcache() | 原始统计函数,按 queryid、userid、dbid、top 维度输出 |
| pg_stat_kcache_detail | 关联 pg_stat_statements 后的明细视图,包含 SQL 文本、库名、用户名 |
| pg_stat_kcache | 按数据库聚合的视图 |
| pg_stat_kcache_reset() | 清空统计,仅管理员可执行 |
如果需要精确关联 pg_stat_statements,建议直接使用 pg_stat_kcache(),并显式关联 s.toplevel = k.top。
十四、参数说明
| 参数 | 默认值 | 生效方式 | 说明 |
| pg_stat_kcache.track | top | SET 或 reload | none 不统计,top 只统计顶层语句,all 包含嵌套语句 |
| pg_stat_kcache.track_planning | off | SET 或 reload | 是否统计规划阶段资源 |
| pg_stat_kcache.linux_hz | -1 | SET | Linux HZ,默认自动探测 |
生产环境一般使用 track = top。只有需要分析函数或存储过程内部 SQL 时,才考虑 track = all。
十六、Q1:创建扩展时报需要 shared_preload_libraries 怎么办?
A:说明没有预加载。修改 postgresql.conf,把 pg_stat_kcache 加入 shared_preload_libraries,然后重启。
十七、Q2:pg_stat_kcache_detail 为空,但为什么 pg_stat_kcache() 有数据?
A:pg_stat_kcache_detail 需要关联 pg_stat_statements。如果 SQL 已被 pg_stat_statements 淘汰,视图里就看不到。可以调大 pg_stat_statements.max,或直接查 pg_stat_kcache()。
十八、Q3:plan_* 字段为什么都是0
A:默认不统计规划阶段。需要时执行:
SET pg_stat_kcache.track_planning = on;
之后新执行的 SQL 才会有规划阶段统计。
十九、Q4:普通用户看不到别人的统计吗?
A:这是预期行为。需要全量视角时授予 pg_monitor。
20、Q5:reset 报权限错误怎么回事?
A:pg_stat_kcache_reset() 是破坏性操作,只允许管理员执行。
21、卸载
DROP EXTENSION pg_stat_kcache;
然后从 shared_preload_libraries 中移除 pg_stat_kcache 并重启数据库。
卸载或重启后,内存中的累计统计会丢失。
22、相关参考
·PostgreSQL 可观测性插件套件使用手册
·pg_profile 插件使用手册