自省 自行 自醒

pgcheck 2.0,焕然一新

Word count: 2.3kReading time: 9 min
2026/05/12
loading

前言

大家好,我是 CC,之前我曾写过一个比较简单的一键运维巡检工具:pgcheck,它最早是基于 Bash 和一批历久弥新的祖传 SQL 拼起来的,优点是直接、简单、拿来就能用;缺点也很明显:工程结构比较粗糙,扩展不够优雅,配置方式也不够清爽,而且也可能带来一系列的安全隐患。

最近我对它做了一轮系统性的重构。这次的目标很明确:新增与保留实用巡检 SQL,同时将 pgcheck 从一个 demo/toy 工具,重构成一个更正式、更容易维护、更适合日常使用的项目。

pgcheck 是什么?

pgcheck 是一个轻量级 PostgreSQL 巡检 CLI 工具,面向 DBA、SRE 和数据库工程师。

它主要用于快速查看 PostgreSQL 实例中的常见运行风险,例如:

  • 连接和活跃 SQL
  • 锁等待和阻塞链路
  • 长事务
  • VACUUM 和 autovacuum 状态
  • 表膨胀、索引膨胀
  • 无效索引、低效索引、未使用索引
  • XID / MultiXID 回卷风险
  • xmin horizon 阻塞来源
  • 复制、复制槽、WAL 保留
  • 临时文件使用情况
  • PostgreSQL 16+ 的 I/O 统计

简单说,它不是为了替代监控系统,而是作为一个现场诊断和日常巡检的小工具。当你登录到一台 PostgreSQL 机器上,想快速知道“这个库现在大概有没有问题”,pgcheck 就是为这种场景准备的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
Commands:
pgcheck alltoast <database> <schema> List TOAST tables in a schema
pgcheck analyze_needed <database> Show tables that need ANALYZE
pgcheck checkpoint Show background writer and checkpointer statistics
pgcheck connections <database> Show connection summary and active queries
pgcheck dbstatus Show database-level statistics
pgcheck freeze <database> Show transaction ID consumption and freeze risk
pgcheck index_bloat <database> Estimate btree index bloat
pgcheck index_create <database> Show CREATE INDEX progress
pgcheck index_duplicate <database> Find duplicate indexes
pgcheck index_efficiency <database> Find low-efficiency indexes
pgcheck index_health <database> Show index details and invalid indexes
pgcheck index_null_risk <database> Find large single-column indexes on high-null columns
pgcheck integer_pk_risk <database> Show int2/int4 primary key capacity risk
pgcheck io Show pg_stat_io distribution by backend and object
pgcheck io_hotspot Show pg_stat_io hotspots by time and operations
pgcheck lock <database> Show lock waits and blocking queue
pgcheck long_transaction <database> Show long-running transactions
pgcheck object <database> <user> Show objects owned by a user and role membership
pgcheck partition <database> Show native and inherited partition information
pgcheck privilege Show current monitoring privileges
pgcheck relation <database> <schema> List table and index size in a schema
pgcheck relconstraint <database> <relation> List constraints and multi-column indexes for a relation
pgcheck reltoast <database> <relation> Show TOAST-related columns for a relation
pgcheck replication Show physical streaming replication status
pgcheck replication_slots Show replication slot xmin and retained WAL
pgcheck table_bloat <database> Estimate table bloat and vacuum blockers
pgcheck temp_files Show active sessions using temporary files
pgcheck unused_indexes <database> Find unused and rarely used indexes
pgcheck vacuum_needed <database> Show tables likely to need vacuum
pgcheck vacuum_queue <database> Show vacuum queue and running vacuum details
pgcheck vacuum_state <database> Show running VACUUM progress
pgcheck wait_event <database> Show wait events and wait event types
pgcheck wal_archive Show WAL archiver statistics
pgcheck wal_generate <wal_path> Show WAL generation speed by scanning pg_wal
pgcheck wal_health Show WAL retention and archiving health
pgcheck wraparound_risk <database> Show XID and MultiXID wraparound risk
pgcheck xmin_blockers Show global xmin horizon blockers
help Show this help
version Show build version

这次最大的变化:从 Bash 重构为 Go

旧版本主要是 Bash 脚本调 psql 执行 SQL。

新版本已经重构为 Go 项目:

  • 单二进制发布,部署更简单
  • SQL 文件通过 Go embed 嵌入二进制
  • 命令统一注册管理
  • 自动检测 PostgreSQL 服务端版本
  • psql 可用时优先使用 psql
  • 找不到 psql 时可回退到 Go 原生驱动
  • 项目结构更清晰,后续扩展更容易

这意味着不再只是“一个脚本集合”,而是开始具备一个正式 CLI 工具该有的样子。

配置方式也变简单了

之前很多参数可以从命令行传,也可以从环境变量传,虽然灵活,但用起来有点散。

新版做了收敛:连接信息、psql 行为、输出风格统一放到 JSON 配置文件中

例如:

1
2
bin/pgcheck --config pgcheck.json dbstatus
bin/pgcheck --config pgcheck.json lock postgres

psql 常见参数也可以配置:

  • quiet 对应 psql -q
  • tuples_only 对应 psql -t
  • no_align 对应 psql -A
  • no_psqlrc 对应 psql -X
  • extra_args 用于透传额外 psql 参数

最大限度得保留 DBA 日常习惯。

整合 postgres-howto 的实践经验

这次重构还有一个重点:把我在另一个项目 postgres-howto in Chinese 中沉淀的一些实用 SQL,逐步整合进 pgcheck

新增或增强的巡检项包括:

1
2
3
4
5
6
7
8
pgcheck xmin_blockers
pgcheck wraparound_risk postgres
pgcheck vacuum_queue postgres
pgcheck unused_indexes postgres
pgcheck integer_pk_risk postgres
pgcheck analyze_needed postgres
pgcheck wal_health
pgcheck replication_slots

这些检查都来自真实运维中比较常见的问题:

  • 为什么 VACUUM 回收不了空间?
  • 是谁卡住了 xmin horizon?
  • 数据库有没有 XID / MultiXID 回卷风险?
  • 哪些表需要 ANALYZE?
  • 哪些索引长期没用?
  • int4 主键是否快用完?
  • WAL 为什么一直增长?
  • 复制槽是否保留了大量 WAL?

这些问题单独看都不复杂,但真正线上排查时,如果没有现成 SQL,会浪费很多时间。

支持 PostgreSQL 16+ pg_stat_io

PostgreSQL 16 引入了一个非常重要的视图:pg_stat_io

新版 pgcheck 增加了两个命令:

1
2
pgcheck io
pgcheck io_hotspot

它们可以帮助查看:

  • read / write / extend / fsync 次数
  • backend / bgwriter / checkpointer / autovacuum 的 I/O 分布
  • relation / temp / WAL I/O
  • evictions、reuses
  • fsync 时间

这对分析 I/O 压力非常有帮助。

比如:

  • 到底是谁在写?
  • 是 backend 在写,还是 checkpointer 在写?
  • autovacuum 是否造成 I/O 压力?
  • checkpoint 是否有尖刺?
  • temp file 是否过多?

如果连接的是 PostgreSQL 16 以下版本,工具会直接提示:

1
pg_stat_io is available only in PostgreSQL 16+.

这也是新版 pgcheck 开始面向新版本 PostgreSQL 能力演进的一个体现。

新增临时文件检测

最近这一版还加入了一个很实用的命令:

1
pgcheck temp_files

它会扫描 PostgreSQL 的 pgsql_tmp 目录,并结合 pg_stat_activity,定位当前哪些会话正在使用临时文件。

这类问题在线上很常见:

  • 排序数据太大
  • Hash Join / Hash Aggregate 溢出
  • work_mem 不够
  • SQL 执行计划不理想
  • 大查询产生临时文件拖慢磁盘

相比只看 pg_stat_database.temp_bytes 这种累计指标,temp_files 更适合做现场定位。

增加权限检查和友好提示

很多 PostgreSQL 巡检 SQL 都需要一定权限。

例如:

  • pg_stat_activity
  • pg_locks
  • pg_stat_replication
  • pg_replication_slots
  • pg_ls_dir
  • pg_stat_file
  • pg_ls_waldir

新版增加了:

1
pgcheck privilege

用于查看当前用户是否具备必要的监控权限,例如:

  • 是否 superuser
  • 是否拥有 pg_monitor
  • 是否拥有 pg_read_all_stats
  • 是否拥有 pg_read_all_settings
  • 是否有 replication privilege
  • 是否能执行部分监控函数

如果执行巡检时权限不足,工具也会尽量给出更明确的建议,比如:

1
2
Recommendation:
GRANT pg_monitor TO <user>;

这点很重要。

一个巡检工具不应该只把 PostgreSQL 的报错原样甩给用户,而应该告诉用户“为什么失败,以及应该怎么处理”。

支持 –show-sql 和 –explain

DBA 对巡检工具天然会有一个问题:

“你这个结果是怎么查出来的?”

所以新版支持:

1
2
pgcheck table_bloat postgres --show-sql
pgcheck wraparound_risk postgres --explain

--show-sql 会输出实际执行的 SQL。

--explain 会说明这个检查项的判断逻辑。

巡检工具越专业,越应该让使用者知道结果从哪里来。最开始的版本就有读者担心安全隐患,跑的 SQL 是啥都不知道,还敢用在生产中吗?

命令命名也做了统一

旧版本里有些命令偏动词,有些偏缩写,有些命名不够统一。

新版做了一些调整,例如:

1
2
3
4
5
6
7
8
vacuum_need      -> vacuum_needed
analyze_need -> analyze_needed
index_low -> index_efficiency
index_null_frac -> index_null_risk
index_state -> index_health
relation_bloat -> table_bloat
xid_wraparound -> wraparound_risk
xmin_horizon -> xmin_blockers

不过为了兼容旧用户,旧命令名仍然保留为 alias。

也就是说,老习惯还能继续用,新命名则更适合后续长期维护。

README 也重写了

这次顺手把 README 也重写成了中英双语版本。

新版 README 包括:

  • 项目介绍
  • 安装和构建方式
  • 配置文件说明
  • psql 参数说明
  • 命令列表
  • 使用示例
  • 项目结构
  • 设计说明
  • Roadmap

代码只是能不能运行,README 决定别人能不能理解、能不能用起来、能不能参与改进。

总结

这次 pgcheck 的变化,不是简单加几个 SQL,而是一次比较系统的升级:

  • 从 Bash 重构为 Go
  • 从脚本集合变成正式 CLI 项目
  • 配置方式更清晰
  • 命令命名更统一
  • README 更完整
  • 整合 postgres-howto 中的实战 SQL
  • 增加 PG16+ pg_stat_io 支持
  • 增加临时文件检测
  • 增加权限检查
  • 增加 --show-sql / --explain

最近折腾这么久,这个版本算是我比较满意的一版了。

它依然保持了 pgcheck 最初的定位:简单、直接、高效,不搞复杂平台,不搞重依赖,只做 PostgreSQL 巡检和现场诊断中真正有用的事情。

后续我还会继续补充更多巡检项,也会考虑增加结构化输出、风险等级、以及不同 PostgreSQL 版本的自动化测试。

项目还在继续打磨中,欢迎大家试用、提 issue,也欢迎把你日常运维中觉得好用的 PostgreSQL SQL 分享出来,一起把这个工具做得更实用。

CATALOG
  1. 1. 前言
  2. 2. pgcheck 是什么?
  3. 3. 这次最大的变化:从 Bash 重构为 Go
  4. 4. 配置方式也变简单了
  5. 5. 整合 postgres-howto 的实践经验
  6. 6. 支持 PostgreSQL 16+ pg_stat_io
  7. 7. 新增临时文件检测
  8. 8. 增加权限检查和友好提示
  9. 9. 支持 –show-sql 和 –explain
  10. 10. 命令命名也做了统一
  11. 11. README 也重写了
  12. 12. 总结