Skip to content

postgresql.conf 主配置 ​

postgresql.conf 是 PostgreSQL 实例的主配置文件,所有与实例行为相关的设置(内存、连接、WAL、日志、优化器代价)默认都从它读取。理解它的语法规则、参数上下文(context)、include 拆分机制与优先级顺序,是后续所有性能调优工作的地基。本节把该文件的每一处细节讲透,并给出可直接落地的工程化组织方案。

前置知识

阅读本节前,建议先了解:PL/Java 与 PL/V8、PostgreSQL 架构概览

基础概念 ​

配置文件的位置 ​

PostgreSQL 的数据目录(data directory,通常称为 PGDATA)里默认放着三个核心配置文件。配置文件不在 PGDATA 中也是允许的,此时需要通过 -c config_file= 显式指定。

文件名作用对应参数修改后生效方式
postgresql.conf主配置:内存、WAL、连接、日志、优化器config_file大部分 SIGHUP,部分需重启
pg_hba.conf客户端认证规则hba_fileSIGHUP
pg_ident.conf操作系统用户到数据库用户的映射ident_fileSIGHUP
postgresql.auto.confALTER SYSTEM 写入,由系统维护自动读取SIGHUP

三个文件的真实路径可以用 SQL 直接查出来,不要靠猜:

sql
SHOW config_file;   -- /var/lib/postgresql/18/main/postgresql.conf
SHOW hba_file;      -- /var/lib/postgresql/18/main/pg_hba.conf
SHOW ident_file;    -- /var/lib/postgresql/18/main/pg_ident.conf
SHOW data_directory;-- /var/lib/postgresql/18/main
text
        postgresql.conf
              │  (解析)
              ▼
   ┌──────────────────────┐
   │  参数定义表(GUC)    │  ◀── 编译时的 boot_val 默认值
   └──────────────────────┘
              │
              ▼
   ┌──────────────────────┐
   │ postgresql.auto.conf │  ◀── ALTER SYSTEM 写入,优先级更高
   └──────────────────────┘
              │
              ▼
   ┌──────────────────────┐
   │  命令行 -c 覆盖       │  ◀── 优先级最高
   └──────────────────────┘

参数上下文(context) ​

每个参数都有一个「上下文」,决定了谁能在什么时候改它。这是 postgresql.conf 里最容易被忽略、但在排查「改了没生效」时最关键的概念。官方在 pg_settings 视图中定义了七类:

context 取值含义修改手段例子
internal编译期固定,不可直接修改只能改代码重编译block_size、wal_block_size
postmaster只能在实例启动时设置改配置 + 重启shared_buffers、max_connections
sighup发 SIGHUP(reload)即可改配置 + pg_ctl reloadlog_min_duration_statement、work_mem 的默认值
superuser-backend超级用户可在连接建立时设置在 postgresql.conf 或连接参数中设置session_preload_libraries
backend后端进程启动时设定由连接来源决定log_connections(新机制下)
superuser超级用户可随时 SET,无需重启SET / ALTER SYSTEMwork_mem、maintenance_work_mem
user普通用户也能为自己的会话设置SETsearch_path、statement_timeout

常说的「五类上下文」是把 backend 与 superuser-backend 合并、把 user 与 superuser 合并后的简化说法。排查问题时请以 pg_settings.context 的实际取值为准。

查询某个参数的上下文:

sql
SELECT name, setting, unit, context, vartype
FROM pg_settings
WHERE name IN ('shared_buffers', 'work_mem', 'max_connections', 'block_size')
ORDER BY name;
text
      name       |  setting  | unit |   context   | vartype
-----------------+-----------+------+-------------+---------
 block_size      | 8192      |      | internal    | integer
 max_connections | 100       |      | postmaster  | integer
 shared_buffers  | 16384     | 8kB  | postmaster  | integer
 work_mem        | 4096      | kB   | user        | integer
(4 rows)

block_size 是 internal,所以你永远无法在配置里改它;shared_buffers 是 postmaster,改了必须重启;work_mem 是 user,每个连接都能自己 SET。

语法规则 ​

postgresql.conf 的语法非常宽松,但要记住四条硬规则:

规则正确写法错误写法
参数名大小写不敏感shared_buffers / SHARED_BUFFERS——
参数名内部的连字符等价下划线max_connections / max-connections——
值用单引号是安全的(推荐)shared_buffers = '4GB'shared_buffers = 4 GB(散落 token)
空白与注释(#)随意# 注释——
ini
# ---- 数值型:可带单位 ----
shared_buffers = 4GB
work_mem = '16MB'
maintenance_work_mem = 512MB

# ---- 布尔型:on/off/true/false/yes/no/1/0 都可 ----
log_min_duration_statement = 1000
fsync = on
autovacuum = 'true'

# ---- 枚举型:不加引号时值必须是单个标识符 ----
wal_level = replica
log_destination = 'csvlog'

# ---- 字符串型:含特殊字符时务必加引号 ----
log_line_prefix = '%m [%p] %q%u@%d '
search_path = '"$user", public'

单位规则(来自官方 config-setting 文档):

  • 内存单位:B、kB、MB、GB、TB,全部是 1024 的倍数(1MB = 1024kB)。
  • 时间单位:us、ms、s、min、h、d。只有毫秒(ms)与秒(s)可以带小数。
  • 不带单位时为该参数的「默认单位」,例如 shared_buffers 默认单位是 8kB 块。

优先级顺序 ​

当一个参数在多个地方出现时,后读取的覆盖先读取的。完整优先级从低到高:

text
1. 编译默认值(pg_settings.boot_val)
2. postgresql.conf(含 include 进来的文件)
3. postgresql.auto.conf   ← ALTER SYSTEM 写入,总能覆盖 postgresql.conf
4. 启动命令行 -c name=value / 环境变量 PGOPTIONS
5. 角色级 / 数据库级 ALTER {ROLE|DATABASE} ... SET
6. 会话级 SET / 事务级 SET LOCAL

postgresql.auto.conf 的覆盖是「无条件」的

只要一个参数在 postgresql.auto.conf 里出现过,postgresql.conf 里对它的设置就会被完全忽略——即使 postgresql.conf 在文件顺序上更靠后也没用。postgresql.auto.conf 是最后读取的,与文件位置无关。

想清掉它,只能使用 ALTER SYSTEM RESET 参数名;,或直接删除该行。

语法与用法 ​

基本格式 ​

ini
# 单行注释用 #
# 参数名 = 值
max_connections = 200

# 值可加引号(推荐用于带空格或特殊字符的值)
log_line_prefix = '%m [%p] user=%u,db=%d,app=%a,client=%h '

# 同一参数可以写多次,最后一次生效(前面的是「废弃/被覆盖」状态)
# 这会被 pg_file_settings 标记出来

同一个参数写多遍时,最后一条生效,并且 pg_file_settings 视图会把前面的记录标记为 applied = f 并给出原因,这是排查「我明明写了却没用」的第一手证据。

include 机制 ​

为了把几千行配置拆成可维护的小文件,PostgreSQL 提供三条指令:

指令行为文件不存在时
include '文件路径'在此处插入该文件内容报错,启动/reload 失败
include_if_exists '文件路径'同上静默忽略
include_dir '目录路径'按文件名排序插入目录下所有 *.conf静默忽略
ini
# postgresql.conf 末尾常见写法
include 'shared.conf'          # 共享内存相关
include_if_exists 'local.conf' # 本机专属覆盖,不存在也不报错
include_dir 'conf.d'           # 目录里所有 *.conf 按名排序读入

include 的路径若为相对路径,相对于当前配置文件所在目录解析,而不是 PGDATA。嵌套 include 允许,且没有深度限制。

include_dir 的排序与过滤规则 ​

include_dir 的行为细节很容易踩坑,官方文档明确规定了三点:

  1. 只读取以 .conf 结尾的文件。
  2. 跳过以 . 开头的隐藏文件(如 .bak.conf 不会被读)。
  3. 文件按 C locale(即字节序) 排序,不是按操作系统的语言环境影响后的词典序。

因此社区约定用数字前缀控制顺序:

text
PGDATA/conf.d/
├── 00shared.conf        # 最先读,基础内存/连接
├── 10logging.conf       # 日志
├── 20planner.conf       # 优化器代价
├── 90local.conf         # 最后的本机覆盖
└── postgresql.conf.bak  # 不会读(不是 .conf 结尾)

常用参数速查表 ​

参数默认值上下文说明
max_connections100postmaster最大客户端连接数(+ superuser_reserved_connections)
superuser_reserved_connections3postmaster保留给超级用户的连接槽
shared_buffers128MBpostmaster共享缓冲池大小
work_mem4MBuser每个排序/哈希节点的可用内存
maintenance_work_mem64MBuserVACUUM / CREATE INDEX 等使用
wal_levelreplicapostmasterWAL 详细程度(minimal/replica/logical)
fsynconsighup是否强制刷盘
synchronous_commitonuser提交是否等待 WAL 刷盘
log_min_duration_statement-1superuser慢查询阈值(-1 = 关闭)
log_destinationstderrsighup日志输出目标
logging_collectoroffpostmaster是否启用日志收集进程
listen_addresseslocalhostpostmaster监听地址
port5432postmaster监听端口
timezone系统决定user时区
default_transaction_isolationread committeduser默认隔离级别
random_page_cost4.0user随机页读取代价

详细说明 ​

一、查看「参数到底从哪里来」 ​

这是排查配置问题的第一招:不要看文件,要看视图。pg_settings 提供 source、sourcefile、sourceline 三个字段,直接告诉你生效来源。

sql
SELECT name, setting, unit, source, sourcefile, sourceline, pending_restart
FROM pg_settings
WHERE name IN ('shared_buffers', 'work_mem', 'max_connections');
text
      name       | setting | unit |       source       |          sourcefile           | sourceline | pending_restart
-----------------+---------+------+--------------------+-------------------------------+------------+-----------------
 max_connections | 200     |      | configuration file | /etc/postgresql/18/main/postgresql.conf |        64 | f
 shared_buffers  | 1048576 | 8kB  | configuration file | /etc/postgresql/18/main/postgresql.conf |        66 | f
 work_mem        | 16384   | kB   | configuration file | /etc/postgresql/18/main/postgresql.conf |        71 | f

若把值改成通过 ALTER SYSTEM 设置,sourcefile 会变成 .../postgresql.auto.conf,这就是最直接的「谁覆盖了谁」的证据。

二、pg_file_settings:reload 前的预检 ​

pg_file_settings 视图逐行列出所有被读到的配置行,并在 applied / error 中给出结果。它只反映文件内容,不反映内存中的实际值,因此非常适合在 reload 之前预检拼写错误。

sql
SELECT sourcefile, sourceline, name, setting, applied, error
FROM pg_file_settings
WHERE error IS NOT NULL OR applied = false
ORDER BY sourcefile, sourceline;
text
     sourcefile      | sourceline |     name      | setting  | applied |        error
---------------------+------------+---------------+----------+---------+---------------------
 /etc/.../postgresql.conf |    120 | shared_buffers | 4GB      | f       | setting is overridden by a later entry
 /etc/.../postgresql.conf |    240 | work_mem       | 8MB      | f       | setting is overridden by a later entry
 /etc/.../postgresql.conf |    305 | log_min_duraton_statement | 1000 | f | unrecognized configuration parameter
(3 rows)

第三行是典型的拼写错误(log_min_duraton_statement 少了一个 i)。这种错误在 reload 时不会导致失败,PostgreSQL 只会记一条警告然后忽略它——所以只看日志经常漏掉,必须查这个视图。

三、pending_restart:哪些改动还没生效 ​

postgresql 上下文(如 shared_buffers、max_connections)的参数改了文件、reload 也不会生效,pg_settings.pending_restart = true 就是提示你还欠一次重启。

sql
SELECT name, setting, unit, pending_restart
FROM pg_settings
WHERE pending_restart
ORDER BY name;
text
       name        | setting | unit | pending_restart
-------------------+---------+------+-----------------
 max_connections   | 200     |      | t
 shared_buffers    | 1048576 | 8kB  | t
 shared_memory_size| 1048576 | 8kB  | t

在自动化运维里,把这个查询挂到监控上,就能在「用户以为已生效、实际没生效」的窗口期发出告警。

四、boot_val / reset_val 与恢复默认值 ​

三个容易混淆的「默认值」概念:

字段含义用途
boot_val编译时的默认值想知道「原始出厂值」
reset_valRESET 之后会变成的值(即配置文件里的值)会话里想恢复配置
setting当前实际生效值日常排查
sql
SELECT name, setting, boot_val, reset_val, source
FROM pg_settings
WHERE name = 'work_mem';
text
   name   | setting | boot_val | reset_val |       source
----------+---------+----------+-----------+--------------------
 work_mem | 32768   | 4096     | 16384     | session

这里 setting = 32768(当前会话 SET 成了 32MB),reset_val = 16384(配置文件的 16MB),boot_val = 4096(编译默认 4MB)。

五、用 ALTER SYSTEM / SET 临时覆盖 ​

不想动文件时,可以用两种方式临时改:

sql
-- 方式一:写进 postgresql.auto.conf(需要 reload 或自动生效),影响所有会话
ALTER SYSTEM SET work_mem = '32MB';
SELECT pg_reload_conf();

-- 方式二:只影响当前会话
SET work_mem = '64MB';

-- 只影响当前事务,事务结束自动还原
BEGIN;
SET LOCAL work_mem = '128MB';
SELECT ...;
COMMIT;  -- work_mem 自动回到之前的值

ALTER SYSTEM 会成为持久配置;SET 只活在会话里。生产环境做临时救火推荐 SET,因为它的作用范围可控、不留垃圾。

六、配置文件的读取顺序演示 ​

把优先级写进一个可复现的实验:

ini
# postgresql.conf
work_mem = '16MB'
sql
ALTER SYSTEM SET work_mem = '8MB';
SELECT pg_reload_conf();
sql
-- 结果:auto.conf 赢了
SHOW work_mem;   -- 8MB
SELECT setting, source, sourcefile FROM pg_settings WHERE name = 'work_mem';
text
 setting |       source       |              sourcefile
---------+--------------------+--------------------------------------
 8192    | configuration file | /var/lib/postgresql/18/main/postgresql.auto.conf

即使 postgresql.conf 里也写了 16MB,postgresql.auto.conf 依然覆盖它。要恢复,执行:

sql
ALTER SYSTEM RESET work_mem;
SELECT pg_reload_conf();

七、角色级与数据库级默认值 ​

PostgreSQL 允许为某个角色或某个数据库设置默认参数,作用范围介于 postgresql.conf 与 SET 之间:

sql
-- 给批处理角色单独放大内存
ALTER ROLE etl_worker SET work_mem = '256MB';
ALTER ROLE etl_worker SET maintenance_work_mem = '2GB';

-- 给报表库单独设置
ALTER DATABASE analytics SET work_mem = '64MB';
ALTER DATABASE analytics SET jit = off;

这些设置存储在系统目录里(不是配置文件),并且会在会话建立时应用。优先级:SET > 角色级 > 数据库级 > postgresql.auto.conf > postgresql.conf。

查看某角色/数据库的专属设置:

sql
SELECT rolname, rolconfig FROM pg_roles WHERE rolconfig IS NOT NULL;
SELECT datname, datconfig FROM pg_database WHERE datconfig IS NOT NULL;

八、SHOW ALL 与 SET 的可用范围 ​

SHOW ALL 会列出所有参数及其当前值,但输出很长,建议过滤:

sql
-- 只看与内存相关的
SELECT name, setting, unit FROM pg_settings WHERE name LIKE '%mem%' OR name LIKE '%buffer%';

-- SHOW ALL 的 SQL 等价写法
SELECT name, setting, unit, category, short_desc FROM pg_settings ORDER BY name;

pg_settings 的 setting 列可以直接 UPDATE,效果等同于 SET:

sql
UPDATE pg_settings SET setting = '32MB' WHERE name = 'work_mem';
-- 等价于 SET work_mem = '32MB';

这在用只能执行 SELECT/UPDATE 的工具(如某些 BI 客户端)调参时偶尔有用,但脚本里不要这么写,可读性差且容易被误认为是改了系统表。

九、配置文件中的特殊值写法 ​

有些参数的值包含特殊字符(如 search_path、log_line_prefix、TimeZone),引号策略需要特别注意:

ini
# 含空格/逗号/特殊字符,必须引号
log_line_prefix = '%m [%p] %q%u@%d '
search_path = '"$user", public, extensions'
timezone = 'Asia/Shanghai'
DateStyle = 'ISO, MDY'

# 枚举值只有单个标识符时可以不引号,但引号更安全
wal_level = 'replica'
synchronous_commit = 'on'

在 SQL 里设置时,因为要用字符串字面量,需要双层引号:

sql
SET search_path = '"$user", public';
ALTER SYSTEM SET log_line_prefix = '%m [%p] %q%u@%d ';

十、用 pg_settings 做配置基线审计 ​

最后给一个实战用的「配置快照 + 差异对比」查询,用于比对主库与从库、生产与测试:

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

把两个实例的这个结果导出来做 diff,就能快速发现「从库配置没跟主库对齐」这类问题。配合 \copy 直接导出:

bash
psql -c "\copy (SELECT name, setting, unit, source FROM pg_settings WHERE source <> 'default' ORDER BY name) TO 'prod.conf.snapshot' WITH CSV HEADER"

实战示例 ​

场景:把散乱的 postgresql.conf 重构为 conf.d 分片管理 ​

一家公司的主库 postgresql.conf 已经 900 多行,运维改一处参数要翻半天,且多人合并时常冲突。目标是拆成 4 个职责清晰的分片,并保证 local.conf 能随时覆盖。

第一步,在主配置末尾加 include 指令(保留原文件其余内容不动):

ini
# ---------- 分片配置 ----------
# 基础资源(内存、连接数):最先读取
include 'conf.d/00resources.conf'
# 日志与审计
include 'conf.d/10logging.conf'
# 优化器与并行
include 'conf.d/20planner.conf'
# 本机/本环境覆盖:最后读取,优先级最高
include_if_exists 'conf.d/99local.conf'

第二步,把原文件里对应段落剪切到分片中:

ini
# conf.d/00resources.conf
listen_addresses = '0.0.0.0'
port = 5432
max_connections = 400
superuser_reserved_connections = 5
shared_buffers = '8GB'
work_mem = '8MB'
maintenance_work_mem = '1GB'
effective_cache_size = '24GB'
wal_buffers = '16MB'
ini
# conf.d/10logging.conf
logging_collector = on
log_directory = 'log'
log_filename = 'postgresql-%Y-%m-%d.log'
log_rotation_age = '1d'
log_rotation_size = '200MB'
log_line_prefix = '%m [%p] %q%u@%d,%a '
log_min_duration_statement = 1000
log_checkpoints = on
log_lock_waits = on
log_temp_files = 0
ini
# conf.d/20planner.conf
random_page_cost = 1.1          # SSD 环境
effective_io_concurrency = 200
default_statistics_target = 200
jit = on
max_parallel_workers_per_gather = 4
ini
# conf.d/99local.conf(不纳入版本库,按机器定制)
# 这台是内存受限的从库,压低内存
shared_buffers = '2GB'
work_mem = '4MB'

第三步,reload 并核对生效情况:

bash
pg_ctl reload -D /var/lib/postgresql/18/main
# 或 sudo systemctl reload postgresql
sql
-- 核对:本机覆盖是否生效
SELECT name, setting, unit, sourcefile
FROM pg_settings
WHERE name IN ('shared_buffers', 'work_mem', 'random_page_cost', 'work_mem');
text
       name       | setting  | unit |                    sourcefile
------------------+----------+------+-------------------------------------------------
 random_page_cost | 1.1      |      | /var/lib/postgresql/18/main/conf.d/20planner.conf
 shared_buffers   | 262144   | 8kB  | /var/lib/postgresql/18/main/conf.d/99local.conf
 work_mem         | 4096     | kB   | /var/lib/postgresql/18/main/conf.d/99local.conf
(3 rows)

结果解读:shared_buffers 与 work_mem 都来自 99local.conf,说明「后面的分片覆盖前面的分片」符合预期(排序靠后 → 后读取 → 生效);random_page_cost 来自 20planner.conf。

第四步,reload 前做一次预检,确保没有拼写错误:

sql
SELECT sourcefile, sourceline, name, error
FROM pg_file_settings
WHERE error IS NOT NULL;
text
 sourcefile | sourceline | name | error
------------+------------+------+-------
(0 rows)

零行代表分片全部解析成功,可以放心 reload。

注意事项 ​

不要直接编辑 postgresql.auto.conf。 该文件由 ALTER SYSTEM 管理,手工编辑的内容会在下次 ALTER SYSTEM 操作时被重写覆盖。

bash
# 错误!手工改 auto.conf 会被系统覆盖
echo "work_mem = 64MB" >> $PGDATA/postgresql.auto.conf

正确做法是用 ALTER SYSTEM:

sql
ALTER SYSTEM SET work_mem = '64MB';

include 的路径不要写相对路径含 .. 的绕行写法。 相对路径是相对于当前配置文件所在目录,写成 include '../shared.conf' 在不同部署方式下会指向不同位置,极易出错。

ini
# 不推荐:依赖当前文件位置,脆
include '../shared.conf'
# 推荐:使用绝对路径或与 PGDATA 明确的相对关系
include '/etc/postgresql/shared.conf'

改了 postmaster 上下文参数后不要以为 reload 就行。 shared_buffers、max_connections、logging_collector 等必须重启,否则你改的值只躺在文件里。

sql
-- 错误认知:reload 后 shared_buffers 就变了
SELECT pg_reload_conf();
SHOW shared_buffers;  -- 依然是旧值
-- 正确检查
SELECT name, pending_restart FROM pg_settings WHERE name = 'shared_buffers';

不要在参数名里用驼峰或随意缩写。 PostgreSQL 参数名是 <prefix>_<unit> 风格,大小写不敏感但不认「近似拼写」。拼错的参数会被静默忽略(只在日志留警告),造成「配置没生效」的假象。

ini
# 错误!这些都不是合法参数名
ShareBuffers = '4GB'
log_min_duration = 1000        # 正确的是 log_min_duration_statement
bogus_param = 'x'

include_dir 里放备份文件是一个隐蔽的坑。 只要文件名以 .conf 结尾就会被读入,把 postgresql.conf.20250101.conf 放在 conf.d/ 里,等于把一份旧配置也叠加进来。

bash
# 错误!备份文件被当成有效分片
cp conf.d/00resources.conf conf.d/backup/00resources.conf.bak   # 安全(非 .conf 结尾)
cp conf.d/00resources.conf conf.d/old.conf                      # 危险!会被读入

不要用超长的单行配置,尤其 log_line_prefix、search_path 这类含空格与引号的值,抄错一个引号就会导致整行解析失败。

ini
# 不推荐:一行塞太多,易错
log_line_prefix='%m [%p] %q%u@%d,%a,%h,%r '
# 推荐:换行 + 明确引号(注意:值本身不能跨行,只是排版建议)

生产环境改配置前务必先做 pg_file_settings 预检。 存在 error 行时,reload 不会中断服务,但会让你以为改了实际没改。

sql
-- reload 前的强制自检
SELECT count(*) AS errors FROM pg_file_settings WHERE error IS NOT NULL;
-- 必须为 0 才 reload

不要把 postgresql.conf 纳入 include_dir 自身。 如果 include_dir 指向 PGDATA 根目录,会递归读到 postgresql.conf 自己(假设它不以 . 开头且以某些方式匹配),造成重复与混乱。分片一律单独放子目录。

ini
# 错误!可能读到自身或其他非预期文件
include_dir '.'
# 正确
include_dir 'conf.d'

从库 postgresql.conf 不要盲目复制主库。 从库的 shared_buffers、max_connections、work_mem 通常应单独设定;复制主库配置会导致从库内存超配或参数不匹配。

sql
-- 对比主从差异
SELECT name, setting FROM pg_settings WHERE source <> 'default';
-- 分别导出后 diff

最佳实践 ​

统一用 conf.d/ 分片管理,并用数字前缀固化顺序。 顺序即优先级,数字前缀让「谁覆盖谁」一眼可读。

ini
include 'conf.d/00resources.conf'
include 'conf.d/10logging.conf'
include 'conf.d/20planner.conf'
include_if_exists 'conf.d/99local.conf'

把「稳定配置」纳入版本库,把「本机差异」放进不纳入版本库的 99local.conf。 这样多机部署时只维护一份基线,机器差异留在本地文件里。

ini
# conf.d/99local.conf — 加入 .gitignore
shared_buffers = '2GB'

所有数值参数都显式带单位。 不带单位时依赖参数的默认单位,极易误读(例如把 shared_buffers = 16384 当成 16GB,实际是 16384 × 8kB = 128MB)。

ini
# 推荐
shared_buffers = '4GB'
work_mem = '16MB'
# 不推荐
shared_buffers = 524288   # 到底是 8kB 块还是字节?

改动后固定执行三步校验:预检 → reload → 核对。 把它写成一个脚本,杜绝人肉遗漏。

bash
# 1. 预检
psql -Atc "SELECT count(*) FROM pg_file_settings WHERE error IS NOT NULL"
# 2. reload
psql -c "SELECT pg_reload_conf()"
# 3. 核对关键参数
psql -c "SELECT name, setting, unit, pending_restart FROM pg_settings WHERE name IN ('shared_buffers','work_mem','max_connections')"

把 pending_restart 纳入监控。 任何 pending_restart = true 都意味着「配置与实际不一致」,应当在维护窗口内尽快重启消化。

sql
SELECT name, setting, pending_restart FROM pg_settings WHERE pending_restart;

尽量用 ALTER SYSTEM 而不是手工编辑文件来改线上参数。 ALTER SYSTEM 会安全地写入 postgresql.auto.conf、自动 reload,并且可以用 ALTER SYSTEM RESET 干净回滚。

sql
ALTER SYSTEM SET log_min_duration_statement = 500;
-- 回滚
ALTER SYSTEM RESET log_min_duration_statement;

把「每会话临时调参」交给角色级默认值或连接池,而不是写进全局配置。 例如批处理需要大 work_mem,用角色级设置比全局放大更安全。

sql
ALTER ROLE etl_worker SET work_mem = '256MB';
ALTER ROLE report_ro SET statement_timeout = '30s';

shared_buffers 改动一定配合操作系统共享内存参数评估。 使用 sysv 共享内存时需同步调整 kernel.shmmax;用默认 mmap 则不必,但仍要评估整体内存预算。

sql
SHOW shared_memory_type;   -- mmap(默认)
SHOW huge_pages;           -- try

保留一份「配置变更记录」。 每次调整写下「改了什么、为什么、预期效果、验证方法」,并用 pg_settings 快照作为附件。配置调优最常见的失败模式是「半年后没人知道当初为什么这么设」。

sql
\copy (SELECT name, setting, unit, source FROM pg_settings WHERE source <> 'default' ORDER BY name) TO 'config-snapshot.csv' WITH CSV HEADER

random_page_cost 这类优化器参数要按存储介质设定,不要照抄网上的值。 SSD 上常见 1.0~1.5,机械盘保持默认 4.0;改完必须用 EXPLAIN (ANALYZE) 验证计划确实变好了。

ini
# SSD 环境(示例,需实测验证)
random_page_cost = 1.1
effective_io_concurrency = 200

永远保留一份可回滚的配置备份。 改之前先复制一份带时间戳的备份,出问题秒回滚。

bash
cp postgresql.conf postgresql.conf.bak.$(date +%Y%m%d%H%M)

定期审计 source <> 'default' 的参数集合。 时间一长,配置里会累积大量「已无必要」的调整,定期清理能避免「参数之间互相打架」。

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

下一节

继续学习:pg_hba.conf 客户端认证

参考链接 ​