☰
PostgreSQL参数查询全指南:从SHOW到pg_settings的完整链路
2026/9/25 3:17:08 网站建设 项目流程

做了这么多年 PostgreSQL 运维和开发,几乎每隔一阵就有人问我同一个问题:到底去哪查数据库当前的参数值?初看这个问题很简单,SHOW work_mem;一行命令就能解决。但当我真去写自动化巡检、或者做一次参数调整前的梳理时,才发现这背后藏着一条从 postgresql.conf 到 pg_settings 的完整链路,官方文档里关于 Settings 的说明分散在好几页,很少有人把它串起来讲。这篇文章我会从最常用的查询方式讲起,理清运行值和文件值的关系、单位换算的坑和权限边界,最后给出一套可以直接拿去用的巡检脚本。适合两类人:一是刚接触 PostgreSQL、总在 psql 里东试西试的新手,二是需要写监控和运维工具的同学。

1. 先看全景:PostgreSQL 设置项的六层来源和两个视图

PostgreSQL 里面"一个参数当前的取值",其实是一个叠加结果。参数值不是只有一个存放位置,而是先有编译进二进制的默认值,然后按优先级逐步被覆盖。我从最底层到最上层列给你:

  1. 编译时内置的默认值。比如不同版本里work_mem的默认值不一样,但这是软件自带的,不依赖任何配置文件。
  2. postgresql.conf 以及 include / include_dir 引进来的所有文件。这是 DBA 最常碰的一层,日常改参数基本都在这。
  3. postgresql.auto.conf。你在 psql 里执行ALTER SYSTEM SET时,会把参数写到这个文件,启动时它会被再次读取并覆盖普通配置项。
  4. 启动命令行的-c参数。这一层在服务器启动时生效,优先级很高,比如postgres -c shared_buffers=256MB。
  5. 数据库级和用户级设置。ALTER DATABASE ... SET和ALTER ROLE ... SET会影响特定库、特定用户新建的会话。
  6. 会话级设置。SET work_mem = '16MB'这类指令,只对当前会话生效。

实际去"查"的时候,绝大多数信息都落在两个系统视图上:

  • pg_settings:运行时真相。能看到当前会话实际生效的值、这个值来自哪一层、是否需要重启。
  • pg_file_settings:配置文件层的快照。直接反映 postgresql.conf 和相关 include 文件的解析结果,但看不到命令行、数据库级、会话级这些动态部分。

理解这个结构,后面很多问题都能自己推导出来。有次我在客户环境发现SHOW shared_buffers显示 128MB,但客户坚持说 postgresql.conf 里写的是 256MB。查了一圈,原来是同参数在后面被另一行配置覆盖回去了,而pg_file_settings里applied = false的那条记录,一下子就把问题暴露了。这类问题的答案永远在这两个视图和这几层来源里,不在别处。

查询目标使用视图说明
当前会话实际生效值pg_settings最终值,含义最明确
值来自哪一层pg_settings.source/sourcefile/sourceline定位来源
配置文件里写了什么pg_file_settings含 include 文件,不含命令行
改完是否需要重启pg_settings.pending_restart为 true 时表示必须重启

2. 三种取数方式对比:SHOW、current_setting() 与 pg_settings 该用哪个

先说结论:交互式排查优先SHOW,写 SQL 表达式和函数优先current_setting(),做巡检和报表直接查pg_settings。

2.1 SHOW:psql 里最顺手的工具

SHOW是 SQL 命令,直接在 psql 里敲就能看到人类可读的结果:

SHOW work_mem; SHOW max_connections; SHOW ALL; -- 输出全部参数

它的好处是省事,SHOW shared_buffers;会直接返回128MB这种带单位的字符串,不用自己换算。但限制也很明显:它没法写进 SELECT 表达式里。SELECT SHOW work_mem;会直接报语法错误;想用绑定参数传参也没门。所以它只适合人坐在终端前一条条查,不适合写进自动化代码里。

2.2 current_setting():SQL 表达式里的正规军

current_setting(name)是函数,可以出现在任意 SQL 表达式里:

SELECT current_setting('work_mem'); SELECT current_setting('max_connections'); -- 参数不存在时不想抛错,用第二参数 missing_ok SELECT current_setting('some_future_param', true); -- 返回 NULL

第二参数missing_ok是 9.6 版本加入的,默认是false,也就是参数不存在会直接抛unrecognized configuration parameter错误。这对写监控的人来说非常关键,后面踩坑部分我会再展开。

2.3 pg_settings:一张啥都能干的配置总表

pg_settings本质是一张视图,每一行是一个参数,列里全是元信息。我最常用的列是这些:

  • name:参数名
  • setting:当前会话实际值(注意:可能是基础单位的裸数字,见第三节)
  • unit:单位
  • vartype:bool、integer、real、string、enum
  • context:该参数的生效机制,比如要不要重启
  • source:当前值来自哪一层
  • boot_val/reset_val:编译默认值 / 重置后的值
  • sourcefile/sourceline:值来自哪个文件的哪一行
  • pending_restart:是否需要重启才能生效

它最大的价值是能过滤、排序、统计。比如我想看所有没走默认值的参数,一条 SQL 就出来了:

SELECT name, setting, unit, source, sourcefile, sourceline FROM pg_settings WHERE source <> 'default' ORDER BY source, name;

2.4 三种方式的特点对比

特点SHOWcurrent_setting()pg_settings
能否出现在 SELECT 表达式不能能本身就是视图
参数不存在时的行为报错默认报错,可传 true 返回 NULL视图里没有对应行
能否支持绑定参数/拼接变量不行可以可以
返回值格式人类可读字符串同 SHOW部分参数是裸数字 + unit 列
过滤排序只能 SHOW ALL 再人眼扫配合函数,一般完整 SQL 能力
典型场景psql 交互排查函数、监控、动态 SQL巡检、报表、变更评估

这里有个印象很深的例子:之前帮一个团队写数据库巡检插件,他们要统计"所有非默认参数",一开始用的是在代码里逐个SHOW然后拼字符串,又慢又容易漏。改成直接查pg_settings之后,一条 SQL 搞定,还能顺便把 sourcefile 和 sourceline 带上,排障效率完全不一样。

3. 单位、类型和 reset_val:为什么看到 16384,其实是 128MB

这是 PostgreSQL 设置查询里最容易看走眼的坑,单独拿出来讲。

3.1 pg_settings.setting 返回的是"裸数字"

pg_settings里带单位参数的setting列,不会帮你换算成人类可读值。举例:

SELECT name, setting, unit FROM pg_settings WHERE name IN ('shared_buffers', 'work_mem');

在我常用的 PostgreSQL 16 实例上,结果是:

name | setting | unit ---------------+---------+------ shared_buffers | 16384 | 8kB work_mem | 4096 | kB

shared_buffers的setting = 16384,配合unit = 8kB,真实值才是16384 * 8kB = 128MB。而work_mem的setting = 4096,配合unit = kB,真实值是 4MB。

但SHOW shared_buffers;和current_setting('shared_buffers')返回的却是128MB这种带单位字符串。也就是说:

  • pg_settings.setting:基础单位裸数值,适合程序计算,不适合人读。
  • SHOW/current_setting():格式化后的值,适合人读,不适合直接做数学运算。

想同时兼顾,可以写个小查询做换算:

SELECT name, setting AS raw_value, unit, CASE WHEN unit IN ('kB', '8kB') THEN pg_size_pretty( setting::numeric * (CASE unit WHEN 'kB' THEN 1024 ELSE 8192 END) ) WHEN unit IN ('ms', 's', 'min') THEN setting || ' ' || unit ELSE setting END AS readable_value FROM pg_settings WHERE name IN ('shared_buffers', 'work_mem', 'checkpoint_timeout');

3.2 布尔值和枚举值的显示规则

SET参数如果是布尔类型,current_setting()返回的是on/off文本,不是 SQL 布尔值。pg_settings里的setting列同样存文本on/off。比如:

SELECT current_setting('autovacuum'); -- on SELECT current_setting('autovacuum') = 'on'; -- true

写监控的人经常会在这里踩坑:直接把current_setting('autovacuum')当成 bool 类型去比较,结果类型对不上。正确姿势是拿出来之后自己转,或者直接比较字符串'on'。

枚举类参数也一样,比如wal_level返回replica、logical等,直接拿文本做判断即可。

3.3 boot_val 和 reset_val 到底差在哪

这两个列长得像,含义完全不同:

  • boot_val:编译进二进制、最近一次启动时的"出厂默认值",它不会因为你改配置文件而改变。
  • reset_val:当前会话执行RESET后得到的值,可以理解为"去掉会话级 SET 之后的值"。

最典型的用法是判断"这个参数到底有没有被人为改过":

SELECT name, boot_val, reset_val, (reset_val <> boot_val) AS customized FROM pg_settings WHERE name IN ('shared_buffers', 'work_mem', 'max_connections');

如果reset_val <> boot_val,说明配置层面做了定制;如果两者相等,说明走的是软件默认值。注意别拿setting和boot_val直接比,因为会话里可能有人SET过,setting会失真,而reset_val才是"配置文件层给的值"。

另外pg_settings还有min_val、max_val、enumvals三列,分别表示合法取值边界和枚举可选项。在写参数校验工具时非常好用,避免你拿一个超范围值去ALTER SYSTEM SET,然后重启失败。

4. 只查运行值会翻车:用 pg_file_settings 看配置文件的真实状态

pg_settings反映的是"当前生效值",但配置文件的真实状态它不一定诚实。比如你在 postgresql.conf 里同一参数写了两遍,后写的覆盖先写的,运行时SHOW出来的自然是后一个值——前一行配置其实根本没生效,但你完全看不出来。这种时候就得查pg_file_settings。

4.1 pg_file_settings 的关键列

这个视图的常见列有:

  • name:参数名
  • setting:配置文件里写的原始值
  • applied:该配置是否被最终采用
  • error:解析或语义错误信息
  • filename:来自哪个文件
  • line_seq:文件内的行序

最经典的排查语句:

SELECT name, setting, applied, error, filename, line_seq FROM pg_file_settings WHERE NOT applied OR error IS NOT NULL ORDER BY filename, line_seq;

applied = false常见原因有两种。第一是同一参数在后面的行、或更高优先级的位置被再次定义,前面的那条就标记为未采用;第二是postgresql.auto.conf里的值覆盖了 postgresql.conf 里的值。error不为空则说明配置参数名拼错、值类型不对或超出范围,比如把max_connections写成字符串 "abc"。

4.2 ALTER SYSTEM 和 postgresql.auto.conf

ALTER SYSTEM SET和ALTER SYSTEM RESET操作的是postgresql.auto.conf,它由服务器自己维护,不需要你手动去碰文件。这个文件在启动时会被读取,而且同样出现在pg_file_settings的解析结果里。

很多人改完ALTER SYSTEM SET之后直接问"为什么 SHOW 出来没变化",原因通常是这个参数属于postmaster级别,比如shared_buffers、max_connections,改完必须重启。判断方法很简单:

SELECT name, setting, pending_restart, source, sourcefile, sourceline FROM pg_settings WHERE pending_restart;

pending_restart = true意味着"配置文件里已经改了,但当前运行实例还没用上"。对sighup级别的参数,执行SELECT pg_reload_conf();就能热加载;对postmaster级别的,只能老老实实重启。

4.3 改了文件之后视图可能还是旧的

这里有个很容易忽视的细节:pg_file_settings保存的是服务器最近一次启动或 reload 时解析出来的结果,并不是实时读盘。你在外面手动改了 postgresql.conf,不执行 reload 直接查这个视图,看到的很可能还是旧内容。

我的标准操作流程是:

  1. 编辑 postgresql.conf。
  2. 执行SELECT pg_reload_conf();触发重新解析。
  3. 再查pg_file_settings验证applied和error。
  4. 最后查pg_settings确认运行值。

顺序反了,经常会被"视图没变化"误导,以为是自己的修改没写进去。

5. 实战:一套可以直接抄走的配置巡检 SQL

说再多不如给能直接跑的东西。以下是我在多个环境里验证过的巡检 SQL 模板,按需取舍即可。

5.1 找出所有非默认参数

这是配置基线检查的第一条,也是升级大版本前的必查项:

SELECT name, setting, unit, source, sourcefile, sourceline FROM pg_settings WHERE source <> 'default' ORDER BY source, name;

需要注意两点:如果当前连接是带业务的高权限连接,会话里可能残留SET留下的source = 'session'记录,建议用一个干净的新连接来跑;如果是监控账号,过滤掉session即可。

5.2 检查配置文件的错误和未应用项

SELECT name, setting, applied, error, filename, line_seq FROM pg_file_settings WHERE NOT applied OR error IS NOT NULL ORDER BY filename, line_seq;

这条我每改一次配置就必跑。尤其是刚接手一套别人管过的数据库,经常能扫出成片的历史垃圾配置。

5.3 检查待重启参数

SELECT name, setting, source, sourcefile, sourceline, pending_restart FROM pg_settings WHERE pending_restart;

结合变更窗口使用:先看有哪些参数只是"纸上改了",等重启窗口到了再统一处理。

5.4 输出人类可读的非默认配置清单

把第三节的单位换算逻辑整合进来,输出一张可以直接贴到变更记录里的表:

SELECT name, setting AS raw_value, unit, CASE WHEN unit IN ('kB', '8kB') THEN pg_size_pretty( setting::numeric * (CASE unit WHEN 'kB' THEN 1024 ELSE 8192 END) ) ELSE setting || COALESCE(' ' || unit, '') END AS readable_value, source, sourcefile, sourceline FROM pg_settings WHERE source <> 'default' ORDER BY name;

这条非常推荐放进巡检脚本里,因为人读配置清单时,16384 + 8kB和128MB的认知成本完全不一样。

5.5 调度建议

把上面 SQL 存成一个config_review.sql文件,cron 里定时跑:

psql -X -A -t -q -f config_review.sql > config_review_$(date +%F).txt

或者接到 Prometheus exporter 的自定义 collector 里,配置变化能直接变成指标曲线。我的经验是:至少每天跑一次非默认参数清单,每周跑一次 pending_restart 清单,不然很容易出现"改完忘了重启"这种低级事故。

6. context、权限与扩展参数:查询前需要知道的边界

6.1 context 决定你能不能改、要不要重启

pg_settings.context这个列很少被新手关注,但它直接决定"这个参数怎么改才能生效":

context含义典型参数
internal服务器内部固定,运行期不可改block_size
postmaster改完必须重启数据库实例shared_buffers、max_connections、wal_level
sighup改完 reload 即可生效checkpoint_timeout、autovacuum
superuser只能由超级用户在运行期 SETlog_min_error_statement
user任何用户都能在会话里 SETwork_mem、statement_timeout

如果你在ALTER SYSTEM SET一个postmaster参数后,忘了检查pending_restart,大概率下次重启前都以为已经生效了。这也是为什么我在巡检 SQL 里一定要带上pending_restart和context两列。

6.2 权限:pg_read_all_settings 与最小权限巡检账号

pg_settings对普通用户基本可读,但官方也提供了预置角色pg_read_all_settings,专门用来保证"能读取全部配置变量,即使部分参数对普通用户做了限制"。我给监控服务建账号时,通常会这样做:

CREATE ROLE monitor LOGIN PASSWORD '...'; GRANT pg_read_all_settings TO monitor; GRANT CONNECT ON DATABASE yourdb TO monitor;

这样监控脚本查pg_settings、pg_file_settings都不会因为权限被卡,又不至于给 DEVELOPER 级的大权限。别偷懒直接拿超级用户账号跑外部巡检工具,出过太多安全事故了。

6.3 扩展参数和带点号的自定义参数

PostgreSQL 允许插件定义自己的 GUC,最常见的就是pg_stat_statements.max这种带点的参数。只要扩展被加载,SHOW和current_setting()都能正常查到:

SHOW pg_stat_statements.max; SELECT current_setting('pg_stat_statements.track');

如果你自己也在应用里用自定义 GUC 存点业务标示,比如myapp.instance_id,记得遵循"带点号前缀 + 模块注册"的规则。查询时也一样,用current_setting('myapp.instance_id', true)时如果模块没加载会返回 NULL,不会炸报错,这是比裸调SHOW更稳的写法。

另外提醒一句:pg_settings会暴露data_directory、config_file、hba_file这类包含服务器文件系统路径的参数。如果要把配置查询能力暴露给低权限业务方,尽量挑字段返回,别把整张pg_settings直接开放。

7. 踩坑记录:几个文档没写但实战一定会遇到的细节

7.1 SHOW 不能写在 SELECT 里,也不能绑定参数

我见过不止一次有人在应用代码里写 "SELECT SHOW work_mem" 然后怀疑人生。SHOW是独立命令,不是函数,必须原样执行。动态 SQL 里想传参数也一样,SHOW ?不成立,得写:

SELECT current_setting($1, true);

JDBC 里用PreparedStatement传参数,这个写法才能真正跑通。

7.2 current_setting 不加 missing_ok 会抛错

写通用查询工具时,参数名是动态传入的,比如从配置表里读一行遍历。如果某个参数名拼错、或者在不同版本里不存在,默认的current_setting('xxx')会直接报错中断整个任务。统一写成:

SELECT COALESCE(NULLIF(current_setting('xxx', true), ''), 'undefined');

这样既不会抛错,也能区分"参数不存在"和"参数值为空字符串"两种情况。

7.3 别拿 pg_settings.setting 去拼告警消息

告警里写"shared_buffers 当前值为 16384"对业务完全没意义,他们只想知道"是不是 128MB"。如果是从pg_settings取数,记得把unit列一起取出来做换算;如果想省事,直接用SHOW或current_setting()拿格式化字符串。这两类值混用是配置对比工具里最常见的 bug 来源。

7.4 改完文件先 reload 再查视图

第三节已经讲过,pg_file_settings是最近一次解析结果的缓存。手动改配置文件不 reload 就查,看到的还是上一版解析结果。我踩过最惨的一次是:自认为在 postgresql.conf 里加了一行shared_buffers,查pg_file_settings没看到,以为是文件名写错,后来才发现只是没 reload。从那之后我把"先 reload、再验证"列进了所有变更 checklist。

7.5 参数名会随版本消失或改名

PostgreSQL 大版本升级后,部分参数会被移除或改名,直接拿旧环境的配置清单去 new 环境执行ALTER SYSTEM SET,很容易报 unrecognized。比如老的checkpoint_segments、wal_keep_segments相关行为就变过。升级前可以用这条把所有要下发的参数名先对一遍:

SELECT name FROM pg_settings WHERE name IN ('param1', 'param2', ...);

也可以在 psql 15 以上的版本用\dconfig命令快速看参数概况,比SHOW ALL输出可读性强很多。

7.6 会话残留 SET 会污染巡检结果

如果你用连接池里的长连接去跑巡检,上一个业务事务里执行的SET statement_timeout = '60s'可能还在当前会话生效,导致pg_settings里source = 'session',你以为是配置漂移,其实只是会话残留。巡检脚本里可以在连接建立后显式执行RESET ALL;,或者干脆用一个专门的新连接来跑。

最后分享一个小技巧:把上面这些查询攒成一个 SQL 文件,用psql -X -A -t -f config_review.sql定时跑,输出丢给告警平台。我每次升级大版本,都会先跑一遍非默认参数清单,逐条对比新旧版本的默认值变化,这招已经帮我避免过两次因为默认参数变化导致的性能回退。祝各位查得明白、改得放心。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询