ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

PostgreSQL参数查询全指南:从SHOW到pg_settings的完整链路

PostgreSQL参数查询全指南:从SHOW到pg_settings的完整链路 做了这么多年 PostgreSQL 运维和开发几乎每隔一阵就有人问我同一个问题到底去哪查数据库当前的参数值初看这个问题很简单SHOW work_mem;一行命令就能解决。但当我真去写自动化巡检、或者做一次参数调整前的梳理时才发现这背后藏着一条从 postgresql.conf 到 pg_settings 的完整链路官方文档里关于 Settings 的说明分散在好几页很少有人把它串起来讲。这篇文章我会从最常用的查询方式讲起理清运行值和文件值的关系、单位换算的坑和权限边界最后给出一套可以直接拿去用的巡检脚本。适合两类人一是刚接触 PostgreSQL、总在 psql 里东试西试的新手二是需要写监控和运维工具的同学。1. 先看全景PostgreSQL 设置项的六层来源和两个视图PostgreSQL 里面一个参数当前的取值其实是一个叠加结果。参数值不是只有一个存放位置而是先有编译进二进制的默认值然后按优先级逐步被覆盖。我从最底层到最上层列给你编译时内置的默认值。比如不同版本里work_mem的默认值不一样但这是软件自带的不依赖任何配置文件。postgresql.conf 以及 include / include_dir 引进来的所有文件。这是 DBA 最常碰的一层日常改参数基本都在这。postgresql.auto.conf。你在 psql 里执行ALTER SYSTEM SET时会把参数写到这个文件启动时它会被再次读取并覆盖普通配置项。启动命令行的-c参数。这一层在服务器启动时生效优先级很高比如postgres -c shared_buffers256MB。数据库级和用户级设置。ALTER DATABASE ... SET和ALTER ROLE ... SET会影响特定库、特定用户新建的会话。会话级设置。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 SHOWpsql 里最顺手的工具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单位vartypebool、integer、real、string、enumcontext该参数的生效机制比如要不要重启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 | kBshared_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.confALTER 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 直接查这个视图看到的很可能还是旧内容。我的标准操作流程是编辑 postgresql.conf。执行SELECT pg_reload_conf();触发重新解析。再查pg_file_settings验证applied和error。最后查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_sizepostmaster改完必须重启数据库实例shared_buffers、max_connections、wal_levelsighup改完 reload 即可生效checkpoint_timeout、autovacuumsuperuser只能由超级用户在运行期 SETlog_min_error_statementuser任何用户都能在会话里 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定时跑输出丢给告警平台。我每次升级大版本都会先跑一遍非默认参数清单逐条对比新旧版本的默认值变化这招已经帮我避免过两次因为默认参数变化导致的性能回退。祝各位查得明白、改得放心。
返回列表