PostgreSQL 数据库内部参数初始化优化

11 阅读11分钟

这个因为是局限在数据库内的调优,参数比较模块化,就没有上一章那么难写了,上一章的服务器环境参数涉及的面略广,而且参数有的关联有的冲突,写起来容易收不住,总感觉一不小心能把自己发散到非洲去。好了废话不多说,直接上货。

模块为什么要调这个模块优化逻辑(核心思路)涉及参数
内存管理决定查询是否走内存还是磁盘,是性能上限核心在“缓存命中率”和“避免内存溢出”之间平衡;控制总内存可控分配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
                     # 建议值 机械盘:4SSD:1.1~2NVME1.0~1.5
                     #这个其实也是近几年固态盘流行起来后多出来优化的参数 
                     
seq_page_cost        # 顺序扫描一页数据的代价,只要不是特殊的存储结构(远程存储,分层存储),就别改

cpu_tuple_cost       # cpu扫一页的代价,越大越倾向于不用seq,越小越容易扫全表

effective_io_concurrency  #统可并发 I/O 的能力- 影响:Bitmap Heap ScanIndex Scan 的并发读能力
                          # NVMe200 ~ 512SSD100 ~ 200HDD2 ~ 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  # 复杂查询建议提高(100500~1000)  
  
  
# =========================  
# 五、Autovacuum(核心稳定性)  
# =========================  
  
autovacuum = on   
autovacuum_naptime = 30s  # 默认1min;高写入场景可降到30s(不要盲目10s)  
autovacuum_max_workers = 5  # 计算:根据IO能力(通常35~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  #自己用随意