这个因为是局限在数据库内的调优,参数比较模块化,就没有上一章那么难写了,上一章的服务器环境参数涉及的面略广,而且参数有的关联有的冲突,写起来容易收不住,总感觉一不小心能把自己发散到非洲去。好了废话不多说,直接上货。
| 模块 | 为什么要调这个模块 | 优化逻辑(核心思路) | 涉及参数 |
|---|---|---|---|
| 内存管理 | 决定查询是否走内存还是磁盘,是性能上限核心 | 在“缓存命中率”和“避免内存溢出”之间平衡;控制总内存可控分配 | shared_buffers work_mem maintenance_work_mem effective_cache_size temp_buffers |
| WAL写入 | 控制事务提交延迟与写入吞吐 | 减少WAL刷盘频率,提高顺序写效率,在“性能 vs 数据安全”之间权衡 | wal_buffers wal_writer_delay synchronous_commit |
| Checkpoint | 决定大规模写入时的IO是否抖动 | 减少checkpoint频率 + 平滑写入,避免周期性IO峰值 | checkpoint_timeout max_wal_size min_wal_size checkpoint_completion_target |
| 连接与并发 | 决定系统并发能力与内存消耗上限 | 限制连接数,避免“连接数 × work_mem”导致资源耗尽 | max_connections superuser_reserved_connections idle_in_transaction_session_timeout |
| 优化器成本模型 | 决定SQL执行计划是否合理(索引/全表扫描选择) | 让成本模型贴近真实硬件(SSD/NVMe),提高执行计划准确性 | random_page_cost seq_page_cost cpu_tuple_cost effective_io_concurrency default_statistics_target |
| Autovacuum | 防止表膨胀、索引失效,是长期稳定性的核心 | 提高触发频率 + 提升处理能力,避免“清理滞后” | autovacuum autovacuum_max_workers autovacuum_vacuum_scale_factor autovacuum_analyze_scale_factor autovacuum_work_mem autovacuum_naptime |
| 日志与诊断 | 用于发现性能瓶颈和调优依据 | 控制日志粒度,既能定位问题又避免日志过载 | log_min_duration_statement log_checkpoints log_autovacuum_min_duration track_io_timing |
接下来一项项进行拆解:
1. 内存管理:
PostgreSQL内存优化,讲究的就是一个缓存数据页的命中率,全局缓存命中率至少95%,再低就属于内存优化不足。讲到这里,命中率定量评估计算,突发负载识别,热点数据工作集估算,破坏缓存的异常SQL读取 这四个内存优化后续评估又是不可不尝的一部分(阿西吧,再发散下去简直没法写了,我先把题目放这,等后续写出来在再更新个超链接)。
回归主题,总的一句话:内存调优 = 数据库缓存(shared_buffers) 与 操作系统缓存(Page Cache)之间的资源博弈 + 多进程内存模型(work_mem)对 OS 的压力控制。 (建议:内存的整体使用量控制在80%,至少给系统留出20%的使用空间。),这里先介绍下相关参数的作用和大概的计算逻辑,剩下的以后再说。
shared_buffers #数据库的共享内存,之前说的缓存命中就在这里,
#建议值:内存的25~40%,一般是40%
work_mem # 各个查询进程排序,hash join, groupby 所用
#计算逻辑:all_mem * 0.8 > share_buffer+work_mem * 连接数 * 放大系数(进程里同时有排序,gourp by等。2~5)
#建议值:32MB(比较保守)
#遵守 整体小,局部大的原则。在进程里单独设置本seesion的参数大小,
#比如某个进程需要大排量内存,可以在前面加上set work_mem=256MB
maintenance_work_mem # 主要用于vacuum,create index,add fk 等操作
# 虽说给的逻辑是 ram*0.1 但是没必要真设几个G,一般1G以内就行
effective_cache_size #主要是给优化器用的,让优化器知道有多少共享磁盘缓存
# share_buffer + os cache (0.6*ram)
# 其实还好,多少 没有太严重的影响
temp_buffers #给临时表用的缓存,默认值为8M,一般情况下不用调,场景特殊,比如复杂的查询语句且临时表数据过大,可适量增加
# 8~64MB
2. WAL日志+Checkpoint刷盘写入:
WAL日志也算是PG的核心模块了,这一块的优化逻辑是减少刷盘频率,间接提高顺序写的效率,和checkpoint的链接异常紧密,这两个基本可以写一起,优化逻辑也是相似的。数据库的崩溃复写,流复制,后续的高可用,逻辑订阅等都离不开他,这个都可以值得单开一个章节,这里先只说参数的优化。关于wal日志的内容详解,文件流转规则,日志定位等内容我这先留个标题,后面慢慢写。
wal_buffers # 刷盘前wal日志的缓存大小,这里以前的默认值是64KB,这是真的小,新版是4MB,也不是太大
# 服务器磁盘充裕 min(16MB, shared_buffers × 0.03)
wal_writer_delay # 缓存刷盘后多久才会再刷, 默认是200毫秒
# 基本不用改,但是写的任务量比较少的话,可以适当拉长。
synchronous_commit # 声明一个事务是否写到wal日志里,才返回成成功
# 设置off会提升效率但是会有丢失数据的风险。
# session 级别日志,确定不重要的数据可以设置成off。
checkpoint_timeout # 两次checkpoint的最大时间间隔
# 减少checkpoint频率,建议5-15min(太大 → recovery慢)
max_wal_size #WAL触发checkpoint阈值, 控制checkpoint频率太小
# 推荐值是4~16GB
checkpoint_completion_target # 两个时间检查点的间隔的百分之多少完成任务,使io平滑写入的关键参数
# 这个默认值是0.5, 一般设置成0.9
min_wal_size #WAL最小保留, 防止频繁回收
#max_wal_size/4
注:这里面有一个有点反直觉的点,按照buffer-> flush的策略,应该是刷盘时间间隔越长越容易出现io的尖峰。
关键点两个:
1. wal日志是wal日志,checkpoint是checkpoint,这两一个是作用到日志上,一个作用到真正的数据文件上,完全不同的位置。而且wal是顺序写,写入间隔时间也不长。
2. checkpoint虽然是随机写,但是不是全速写入的,是按照一定的速率匀速写入的,就是在checkpoint_completion_target这个参数,
这里面有个很缺德的一点,max_wal_size 不是wal日志的最大保有量,wal日志也没有最大保有量 ,单节点的时候可以算保有量。
但是archive开的时候,一旦归档出问题了,就容易爆盘
3. 连接与并发 :
连接这个模块没啥好说的,主要是通过限制链接数来控制住内存的变化,主要是防住 connection_num * work_memory 这个量上来别把系统内存给爆了。这里其实还有一个问题,应用一般是通过连接池连接数据库的,但是有的连接池会把住几个连接常年不释放,会让session的内存逐渐膨胀,这个有一整套的处理方法,从参数,到语句,到插件都有处理方法,后续我专门写篇文章
max_connections # 最大连接数
# 建议值 300 左右。
# 不建议通过参数来控制连接数,通过连接池来控制更好
superuser_reserved_connections # 超级连接,防止系统锁死的
# 建议值 3~8 都行,反正是紧急使用的
idle_in_transaction_session_timeout # 空闲连接超时时间
# 建议值: 1~ 10min,按照业务需求调
4. Autovacuum自动清理
自动清理也是数据库的核心模块,用来清理掉PostgreSQL数据库的行MVCC机制产生的各种不用的旧版本行,更新统计信息。这个调不好小心出现事务冻结,到时候就得上vacuum FREEZE了,话说喊了这么多年的32位改64位到现在也没有实现,这都到版本17了.... 这里面其实也有好些内容可以写,比如执行过程(用到的锁,冲突处理,事务冻结)等我后面再出内容
autovacuum # 自动清理的开关,千万不能关
autovacuum_max_workers # 自动清理的进程数,一般建议5~10,我一般给8或者15个
autovacuum_vacuum_scale_factor # vaccum 触发比例
autovacuum_vacuum_scale_threshold # vacuum 触发行数,值自己设
# 建议值0.01 ~ 0.05
# 表级参数,热表改小点,中间涉及到的饱和度分析以后再写
autovacuum_analyze_scale_factor # 自动分析的触发比例
autovacuum_analyze_scale_threshold # 自动分析触发行数,值自己设
# 建议值0.01 ~ 0.02
# 表级参数,热表改小点。
autovacuum_work_mem # 清理进程使用的内存
# 建议值 512~1G, 有需要再调
autovacuum_naptime # 扫描间隔, 建议值10s
autovacuum_cost_delay # vacuum 执行完一批数据页后申请的延迟时间
# 默认20ms,有需求可以调成2ms,其实后续版本调了
autovacuum_cost_limit # vacuum 的
# 机械盘1000~3000,固态盘 10000
PS:在这里参数不太全,将就着看,本来正常来说这里是需要分成3块的, vacuum,autovacuum,事务年龄,这三块。后面写vacuum和事务年龄机制结构详解的时候再说吧。这里基本已经配齐了,日志年龄不用调,后续吧估算方法慢慢写出来。
5.优化器成本模型
这一块后续也需要慢慢写,比如如何优化器的执行逻辑,手动计算执行计划的时间成本,等.....优化原则就是上面表格说的,目的是让执行计划更加贴合实际。老实说这一块,前些年调优的时候根本没有,也是因为最近几年固态不值钱了,笔记本都敢上1T了才出现这样的情况,放以前,根本不存在的.....
random_page_cost # 随机 I/O(Index Scan)比顺序扫描贵多少倍,越小越index scan
# 建议值 机械盘:4,SSD:1.1~2,NVME:1.0~1.5
#这个其实也是近几年固态盘流行起来后多出来优化的参数
seq_page_cost # 顺序扫描一页数据的代价,只要不是特殊的存储结构(远程存储,分层存储),就别改
cpu_tuple_cost # cpu扫一页的代价,越大越倾向于不用seq,越小越容易扫全表
effective_io_concurrency #统可并发 I/O 的能力- 影响:Bitmap Heap Scan,Index Scan 的并发读能力
# NVMe:200 ~ 512,SSD:100 ~ 200,HDD:2 ~ 4
default_statistics_target # 表示:统计信息采样精度 默认100 ANALYZE 收集多少统计样本
# 影响:直方图精度,NDV(distinct值)估计,where 条件选择率估计
# 100:粗略统计(默认)200~500:通用推荐 1000+:高精度(但 ANALYZE 慢)
6.日志与诊断
这个也没有太直接的效果,但是调优的主要依据,用于发现性能瓶颈和调优依据。需要控制日志粒度,既能定位问题又避免日志过载。而且排查的时候,和日常运行的时候,日志的颗粒度也是不一样的。这个比较简单
log_min_duration_statement #这个估计是最熟的,用来抓历史慢SQL的。没有推荐值,按需调整,太小小心日志量爆炸。
log_checkpoints # checkpoint的日志,用来查checkpoint的,自己用随意,生产环境没事不要开。
log_autovacuum_min_duration # vacuum的运行日志,和checkpoint差不多,生产环境没事不要开。
track_io_timing # 抓对应sql的io统计的日志,相当于随时给你analyze了,需要的时候再开。
紧接着上一版,这一篇写着也感觉会到处发散,不过这次学乖了,我只写个标题或者要点在这里,先挖坑后续慢慢填。老规矩,给出一版推荐参数设置,不过这次除了标注的可以直接使用。
# =========================
# 一、内存管理(核心)
# =========================
shared_buffers = 8GB # 计算:≈ 20%~40% RAM
work_mem = 32MB # 计算(RAM - shared_buffers) / (max_connections × 并发系数[2~4])
maintenance_work_mem = 1GB # 计算:≈ 5%~10% RAM
effective_cache_size = 24GB # 计算:≈ 60%~75% RAM(shared_buffers + OS cache)
temp_buffers = 32MB # session级,控制临时表缓存
# =========================
# 二、WAL日志(关键)
# =========================
wal_buffers = 16MB
checkpoint_timeout = 15min
max_wal_size = 8GB # max_wal_size ≈ WAL生成速率 × checkpoint_timeout × 1.5 WAL速率需通过监控估算(MB/s)
min_wal_size = 2GB # ≈ max_wal_size / 4
checkpoint_completion_target = 0.9
# =========================
# 三、并发控制
# =========================
max_connections = 200
superuser_reserved_connections = 5
# =========================
# 四、优化器(成本模型)
# =========================
random_page_cost = 1.1 # SSD: 1.1~1.5 NVMe: 接近 1.0
seq_page_cost = 1.0
effective_io_concurrency = 200 # SSD: 100~200 NVMe: 200~300
default_statistics_target = 500 # 复杂查询建议提高(100→500~1000)
# =========================
# 五、Autovacuum(核心稳定性)
# =========================
autovacuum = on
autovacuum_naptime = 30s # 默认1min;高写入场景可降到30s(不要盲目10s)
autovacuum_max_workers = 5 # 计算:根据IO能力(通常3→5~10)
autovacuum_vacuum_scale_factor = 0.02
autovacuum_vacuum_threshold = 50
autovacuum_analyze_scale_factor = 0.01
autovacuum_analyze_threshold = 50
autovacuum_work_mem = 512MB # 总占用 = autovacuum_max_workers × work_mem 建议 < 20% RAM
autovacuum_vacuum_cost_limit = 1000
autovacuum_vacuum_cost_delay = 2ms
autovacuum_freeze_max_age = 2000000000
vacuum_freeze_table_age = 150000000
vacuum_freeze_min_age = 50000000
# =========================
# 六、日志与诊断
# =========================
log_min_duration_statement = 500ms
log_checkpoints = on #自己用随意
log_autovacuum_min_duration = 0
track_io_timing = on #自己用随意