pg_stat_kcache 用来统计 SQL 在操作系统层面的资源消耗,包括 CPU 时间、物理读写、缺页和上下文切换。它通常和 pg_stat_statements 一起使用。支持版本
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 sON s.queryid = k.queryidAND s.dbid = k.dbidAND s.userid = k.useridAND 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。Q5:reset 报权限错误怎么回事?
A:
pg_stat_kcache_reset() 是破坏性操作,只允许管理员执行。卸载
DROP EXTENSION pg_stat_kcache;
然后从
shared_preload_libraries 中移除 pg_stat_kcache 并重启数据库。卸载或重启后,内存中的累计统计会丢失。