前言:
postgresql数据库作为一个比较重型的数据库,其中的一个突出优点是该数据库开箱即用,基本上只要部署好后,简单的参数调整后就可以应用在生产环境,当然这个前提是不考虑性能参数调优
这里有一个逻辑,简单说就是postgresql数据库的默认参数问题,该数据库的默认参数基本都是最保守的参数,这里可以分为两个层面理解:
第一个层面是默认参数非常稳定,基本不会出现各种意外,也就是俗称的坑
第二个层面是默认参数意味着该数据库有很大的提升空间,也就是性能调优后,性能的提升或降低基本上都是肉眼可见的那种,如果性能参数设定不当,可能会造成比较大的严重事故;如果性能参数设定比较符合实际生产需要,则可能会给数据库带来质的性能飞跃。
也就是说,数据库性能调优可能是一个双刃剑,是有可能出现反向调优的情况,因此,postgresql的参数如何设定就需要慎之又慎。
那么,这个性能调优工作我们应该是在什么时候进行呢?是在性能出现瓶颈的时候再进行性能调优还是再数据库安装部署后就开始呢?
我认为,数据库调优工作应该是一个长期的,延续的,从数据库安装部署后就应该开始进行的工作,而这些数据库参数并不是一成不变的,第一次调优完成后就永远不变的,是应该随着业务负载量这一个动态变化而同步进行的动态变化,同时,数据库的参数应该是一个多维度,立体的设定,比如,某个参数是用户级别的,这个参数也可以是数据库级别的。
ok,这就带出了一系列的问题:
- postgresql数据库有哪些参数是我们修改过的,而非使用的默认值?
- postgresql数据库的参数我们设定的级别是哪个?为什么要设定这个级别或者说为什么要设定为那个级别?
- 哪些postgresql数据库的参数是需要重启数据库才可以生效的?
- 如何安全平滑的修改postgresql数据库的各种参数?
下面我将就这些问题做一个尽量详细的总结。
一、
postgresql参数设置方法的简单介绍
postgresql数据库参数设定一般是以postgresql.conf 也就是主配置文件为主,但还可以写在postgresql.auto.conf 这个配置文件里,除了这个两个配置文件以外,还可以利用SQL命令更改,也就是三个入口途径。
对于参数更改后如何生效的问题,有的参数更改完毕后需要重启数据库才可以生效,也就是配置冷更新;有的参数修改完毕后不需要重启数据库,只需要重载配置文件就可以了,也就是配置热更新,类似于nginx的配置文件更改;还有的参数立刻生效,什么都不需要做,立刻生效,但对于旧会话不生效,只对新会话生效
ok,很多小伙伴可能会懵圈了:postgresql数据库的参数配置也太tm灵活了吧,怎么知道这个参数更改完毕后需不需要重启数据库生效呢?
两种判断方式,第一个是查看 postgresql.conf这个数据库主配置文件
它的注释那写了需要restart,那么,该参数修改后生效就必须重启,如果没用写需要restart,那么,一般热更新就可以了,如下图:

这里配置文件的注释比较详细的说明了比如,shared_buffers的最小值,默认是128MB,如果更改了此值,需要重启数据库才可以生效;huge_pages = try 该参数可选值是on, off, or try这三个,如果更改了此值,需要重启数据库才可以生效;work_mem = 4MB这个参数不需要重启,因为对应的注释没用写restart;shared_memory_type = mmap 这个参数可选值三个,如果更改了此值,需要重启数据库才可以生效;
那么,这个判断方式有时候有点笼统,不精确,最为精确的方式就是第二种方式:查询该数据库的系统视图---pg_settings,只是稍微有点繁琐
postgresql数据库每个参数都有上下文,根据上下文定义参数修改后的生效方式,所有参数都存在pg_settings这个系统视图里
bash
SELECT DISTINCT context FROM pg_settings ORDER BY context;
以上SQL语句输出如下

| 上下文(Context) | 含义 | 生效方式 | 常见例子 |
|---|---|---|---|
**internal** |
内部参数 | 编译时固定,无法修改。 | 如数据块大小等编译选项。 |
**postmaster** |
主进程参数 | 修改配置文件后,必须重启PostgreSQL服务。 | port, shared_buffers, max_connections。 |
**sighup** |
主进程参数(可重载) | 修改后,向主进程发送 SIGHUP 信号(执行 SELECT pg_reload_conf();)即可生效,无需重启。 |
日志相关参数(log_statement)。 |
**backend** |
后端进程参数 | 修改后,新的数据库连接会读取新值。现有连接不受影响。执行重载即可。 | random_page_cost, effective_cache_size。 |
**superuser** |
超级用户参数 | 超级用户可以在会话中随时用 SET命令修改,仅影响当前会话。 |
maintenance_work_mem。 |
**user** |
用户级参数 | 普通用户就可以在会话中随时用 SET命令修改,仅影响当前会话。 |
work_mem, TimeZone。 |
1、internal上下文
这些参数是编译时使用的参数,主要就三个,--with-blocksize=128 --with-wal-blocksize=128 --with-wal-segsize=64,对应在postgresql的主配置文件里如下:
bash
SHOW wal_segment_size;
SHOW block_size;
SHOW wal_block_size;
在11版本之前,这三个参数确实是都需要源码编译才可以改变,但wal-segsize也就是wal日志文件大小在11版本后,可以通过pg_resetwal命令来进行重置,其它两个参数仍然需要编译时候指定,如没用指定,将使用默认值;也可以通过初始化命令initdb,在初始化的时候指定
pg_resetwal --wal-segsize=32 /data/pgdata #需关闭数据库后,执行此命令重新设置wal-segsize的大小,会影响wal日志大小,此命令比较危险,不推荐执行
initdb -E UTF8 --locale=C --wal-segsize=64 -D /home/pg11/data01 -U postgres #初始化的时候指定大小
2、postmaster上下文
此类参数通常是数据库端口,数据库连接数这些设置,都是必须重启数据库才可以生效,这些参数占比比较少
3、sighup上下文
此类参数主要是日志相关参数,只需要重载配置文件,也就是执行 SELECT pg_reload_conf()函数即可生效
4、backend上下文
此类参数修改完毕后,立刻生效,不需要重启数据库,也不需要执行 SELECT pg_reload_conf()函数,只对修改后的连接事务生效,也就是backend类参数,新设置仅对新连接有效,可以使用alter命令修改,会立刻生效
5、****superuser上下文和superuser-backend上下文
超级管理员权限可以设置的参数,会话级别的,影响有限,主要作用是数据库维护工作的时候,临时调整,加快维护进度,可以使用alter命令修改,会立刻生效
**6、user**上下文
普通用户也有权限更改的参数,但只是会话级别,这个级别的参数有些我们是希望固定的,基本变化不大的,例如work_mem,可以使用alter命令修改,会立刻生效
ok,开始实操
二、postgresql数据库参数修改实操示例
1、
查询某个参数的上下文:
bash
SELECT name, context, unit, setting, boot_val, reset_val
FROM pg_settings
WHERE name = 'work_mem';
输出如下:

说的是该参数是用户级别的,也就是可以设置为会话级别,单位是kb,目前设置的是4096kb,也就是4M,在主配置文件postgresql.conf 里也可以看到,确实是默认值

2、
参数上下文的分布情况简介
总共有多少个参数以及每种上下文是多少个(总计是322个,user级别的占比做多,123个,其次是热更新就可以生效的sighup,80个,再次是需要重启的,59个,superuser级别其实可以并入user):
bash
SELECT count(1) FROM pg_settings --322
SELECT * FROM pg_settings WHERE context='user' --123
SELECT * FROM pg_settings WHERE context='postmaster' --59
SELECT * FROM pg_settings WHERE context='internal' --17
SELECT * FROM pg_settings WHERE context='sighup' --80
SELECT * FROM pg_settings WHERE context='backend' --2
SELECT * FROM pg_settings WHERE context='superuser' --37
SELECT * FROM pg_settings WHERE context='superuser-backend' --4
3、
postgresql数据库参数配置生效等级
PostgreSQL 参数配置包罗万象,可以在配置文件 , alter system , 命令行 , 用户 , 数据库 , 所有用户 , 会话 , 事务 , 函数 , 表 等层面进行配置,非常的灵活。灵活是好,但是可配置的入口太多了,优先级如何?如果在多个入口配置了同一个参数的不同值,最后会以哪个为准?
下表为准:
| 配置层级 (优先级从低到高) | 设置方法举例 | 生效范围与特点 |
|---|---|---|
**1. 实例级 (postgresql.conf)** |
编辑配置文件:shared_buffers = '1GB' |
作为系统级默认值 ,影响整个数据库实例。优先级最低,为其他所有设置提供基础值。 |
**2. 实例级 (postgresql.auto.conf)** |
ALTER SYSTEM SET work_mem = '10MB'; |
由ALTER SYSTEM命令管理,优先级高于 postgresql.conf。便于通过SQL动态管理实例级配置。 |
| **3. 命令行级 (启动参数)** | pg_ctl start -o "-c work_mem='20MB'" |
在服务启动时通过命令行指定,优先级高于配置文件。通常用于特殊启动场景。 |
**4. 全局用户级 (ALTER ROLE ALL)** |
ALTER ROLE ALL SET work_mem = '5MB'; |
对所有数据库用户 生效(ALL)。为一个实例下所有用户设置统一参数时非常有用。 |
**5. 数据库级 (ALTER DATABASE)** |
ALTER DATABASE mydb SET work_mem = '15MB'; |
对特定数据库 的所有连接生效。适合为不同业务数据库(如报表库、业务库)设置不同参数。 |
**6. 用户级 (ALTER ROLE)** |
ALTER ROLE analyst SET work_mem = '50MB'; |
对特定用户 的所有会话生效。可为执行特殊任务(如数据分析师)的用户分配更多资源。 |
**7. 会话级 (SET)** |
SET work_mem = '100MB'; |
仅在当前数据库连接会话 中生效,会话结束即失效。灵活性最高,用于临时调整当前操作。 |
**8. 事务级 (SET LOCAL)** |
BEGIN; SET LOCAL work_mem = '200MB'; ... COMMIT; |
仅在当前事务 内有效,事务结束后恢复为会话级设置。用于事务内的特定操作。 |
**9. 函数级 (CREATE FUNCTION ... SET)** |
CREATE FUNCTION ... SET work_mem = '1MB'; |
仅在该函数执行期间生效。实现函数级别的资源隔离与优化。 |
这里有几个误区:
- 1、不是所有写在postgresql.conf 或者postgresql.auto.conf配置文件里的配置都需要重启数据库才可以生效,是否冷热更新配置只取决于pg_settings这个系统视图里定义的上下文
- 2、show命令和SELECT current_setting('work_mem'); 是读取的postgresql.conf 或者postgresql.auto.conf配置文件
- 3、当前会话和新会话不是一个东西(有点点废话文学了)
4、
数据库参数优先等级验证小实验
数据库主配置文件内work_mem 修改为48MB,然后执行SQL : ALTER DATABASE postgres SET work_mem = '64MB'; ,此时不重启数据库,也不执行配置热更新:SELECT pg_reload_conf();navicat要重新开窗口
在navicat里用show命令或者current_setting函数查看,此时work_mem的值是多少呢?(注意,当前窗口查询不会变,必须新会话也就是新开窗口)
答案是64MB。通过此小实验我们可以得出alter databse命令优先级是比配置文件高的,另一个角度也说明参数是user级别的上下文是立刻生效的
总结如下:
| 参数上下文 | 能否用 ALTER DATABASE修改? |
生效时机与条件 | 示例参数 |
|---|---|---|---|
**user** |
可以 | 新建立的会话 生效。对于已经存在的连接到该数据库的会话,不会改变其参数值。 | work_mem, search_path |
**superuser** |
可以(需超级用户权限) | 新建立的会话生效。已有会话不受影响。 | maintenance_work_mem |
**sighup** |
不可以 | 不适用。此类参数通常需要使用 ALTER SYSTEM修改,然后执行重载(SELECT pg_reload_conf();)使新值对所有新老会话生效。 |
log_statement |
**postmaster** |
不可以 | 不适用。此类参数必须修改配置文件并重启数据库才能生效。 | shared_buffers, port |
5、查看所有通过alter命令修改的参数
alter命令如下:
bash
ALTER DATABASE postgres SET work_mem = '22MB';
如果有很多alter databse命令修改过的参数,如何知道呢?SQL如下:
bash
SELECT
COALESCE(datname, '所有数据库') AS 数据库,
COALESCE(rolname, '所有用户') AS 用户,
setconfig AS 参数设置
FROM
pg_db_role_setting s
LEFT JOIN pg_database d ON s.setdatabase = d.oid
LEFT JOIN pg_roles r ON s.setrole = r.oid;
示例输出如下(aleter命令执行完毕后,立刻可以在此SQL显示出来):

下面两个SQL也是和上面的SQL基本等价的:
bash
-- 查找用户 'postgres' 的参数设置
SELECT setconfig
FROM pg_db_role_setting s
JOIN pg_roles r ON s.setrole = r.oid
WHERE r.rolname = 'postgres';
-- 查找数据库 'postgres' 的参数设置
SELECT setconfig
FROM pg_db_role_setting s
JOIN pg_database d ON s.setdatabase = d.oid
WHERE d.datname = 'postgres';
6、参数修改的经验总结:
- 1、postgresql数据库的参数设定一般以主配置文件为主,各个参数以上下文界定,调整参数的时候,先查清楚是哪个上下文级别的,然后在确定修改到哪个值。
- 明确四类关键上下文(context) 及其生效机制,这是所有操作的基石。
- •
postmaster:修改后必须重启数据库服务(如shared_buffers,max_connections)。 - •
sighup:修改后执行SELECT pg_reload_conf(); 即可全局生效(如日志类参数,archive_command这样的参数)。此类参数通常是在配置文件里修改,不可使用alter database/role命令,多数sighup参数是全局性的,重载后对所有现有会话和新会话都生效。建议使用alter system命令修改,写入postgresql.auto.conf 文件内,例如ALTER SYSTEM SET archive_command = '你的新命令';SELECT pg_reload_conf(); - •
backend: 需要重载配置且仅对新会话生效)---如ignore_system_indexes,这个级别的很少,就2个参数 - •
user/superuser:通常在会话中直接用SET修改,仅影响当前会话,如确实有修改的需要,使用类似ALTER ROLE postgres IN DATABASE postgres SET work_mem = '256MB'这样的精细化命令即时修改生效,并持续观察 - 2、全局参数尽量不修改,参数修改只以alter database或者alter user局部设定,并在修改后,重新开启新会话验证是否修改成功。当然,也可以使用像这样的命令 ALTER ROLE postgres IN DATABASE postgres SET work_mem = '256MB';进行更为精细化的参数控制。这是实现配置精细化、减少重启的关键。
- 3、对于postgresql.conf和postgresql.auto.conf,需要调整优化的尽量放置到auto这个配置文件,也就是使用alter system命令设置,第一可以保持主配置文件干净,不臃肿,第二,可以方便确定哪些参数值修改了, 这保证了主配置文件的纯净,并且所有通过SQL进行的持久化修改都有迹可循。
- 4、 postgresql数据库的参数修改建议是先在测试机上测试好后在修改,在生产环境,每一个参数的配置都要慎之又慎,并在修改完毕后,长时间的监控,如果有异常,快速回滚,以避免出现严重的事故(log相关的可以随便改,除非有明确的审计需求)
- 5、postgresql数据库的参数大部分都是即时生效的,但需要注意修改前的会话不受影响,修改后的会话都会应用更改
- 6、ALTER DATABASE postgres RESET work_mem; 这个语句说的是重设为postgresql.conf文件里写的数值,不是初始化数据库时候的参数值,如果postgresql.conf里确实更改过了;
RESET的作用是清除当前层级的设置,让参数值从更高优先级的下一个层级继承。 - 7、没有放之四海而皆准的最优配置。最佳的优化策略始终依赖于你的 具体数据、查询模式、硬件环境和业务需求。持续的监控和分析是数据库性能保持健康的关键。