导读:本期聚焦于赵景明创作的《PostgreSQL的shared_buffers与work_mem参数如何合理配置?一文讲清调优思路》,敬请观看详情。数据库响应变慢、内存占用异常升高,问题往往出在PostgreSQL两个关键内存参数的配置上。shared_buffers决定数据库能缓存多少数据页,设置太小会导致频繁读磁盘,设置过大又会挤压操作系统缓存空间;work_mem控制排序和哈希操作的内存上限,配置不当轻则查询变慢,重则触发OOM。本文从内存分配原理入手,详细讲解这两个参数的工作机制、不同硬件环境下的推荐取值范围,以及如何结合EXPLAIN ANALYZE执行计划判断内存是否够用,同时给出物理内存有限的中小服务器上的实战配置方案,帮助你避开常见的调优误区。

PostgreSQL的内存参数调优里,被问得最多的就是shared_buffers和work_mem这两个。它们一个管共享内存,一个管会话私有内存,作用机制完全不同,但很多初学者会把它们混为一谈,或者照搬网上的数值直接套用,结果数据库性能不升反降。要真正配好这两个参数,得先弄清楚它们各自在查询过程中扮演什么角色,再结合实际的硬件条件和业务负载来定值。

PostgreSQL的shared_buffers与work_mem参数如何合理配置?一文讲清调优思路

先弄懂两个参数的底层机制

shared_buffers是PostgreSQL启动时向操作系统申请的一块共享内存区域,用来缓存数据文件中的数据页。PostgreSQL默认的数据页大小是8KB,当你查询某张表时,系统会先检查这些页是否已经在shared_buffers里,命中就直接读内存,未命中才去磁盘读取。所以这块缓冲区的大小直接决定了缓存命中率,命中率低意味着大量物理IO,性能会明显下降。

work_mem的性质完全不同。它是每个会话在执行排序、哈希连接、哈希聚合这类操作时允许使用的内存上限。注意这里有个非常容易踩的坑:work_mem不是会话级的总量限制,而是单个查询节点级的限制。一条SQL里如果有三个排序节点和两个哈希连接,理论上最多可以同时消耗5倍的work_mem。更麻烦的是,每个并发连接都是独立计算的,100个连接同时跑复杂查询,内存压力会成倍放大。

当排序或哈希操作需要的内存超过work_mem时,PostgreSQL不会报错,而是把中间数据溢出到磁盘的临时文件里继续处理。这就是为什么work_mem设小了会看到查询变慢、pg_stat_activity里出现大量temp文件的原因。反过来设太大,一旦并发上来,内存被瞬间吃光,Linux的OOM killer就可能直接把PostgreSQL进程杀掉。

shared_buffers的推荐值与常见误区

关于shared_buffers,流传最广的说法是设成物理内存的25%。这个经验值对多数场景确实适用,比如一台16GB内存的专用数据库服务器,shared_buffers设4GB是一个不错的起点。但它不是铁律,原因在于PostgreSQL读写数据都要经过操作系统的文件系统缓存,如果shared_buffers占得太高,反而会让OS缓存被挤压,而OS缓存对顺序扫描和写入合并同样重要。

实际调优时可以参考这几个档位:2GB以下内存的小机器,shared_buffers不建议超过512MB,留更多空间给操作系统;4GB到16GB的机器取25%左右比较稳妥;超过32GB的大内存机器上,很多实践表明25%到40%之间都能取得不错效果,但需要配合压测验证。另外一个特殊情况是Windows平台,因为其内存管理机制不同,官方建议shared_buffers不要超过512MB到1GB。

判断shared_buffers是否够用,主要看两个指标:一是pg_stat_database视图中的blks_hitblks_read比例,正常业务系统的缓存命中率应该稳定在99%以上;二是用EXPLAIN (ANALYZE, BUFFERS)查看查询的shared hit与read块数,如果read块数持续偏高,说明数据没被缓存住,可以考虑加内存或者调大shared_buffers。

-- 查看缓存命中率
SELECT datname,
       round(blks_hit * 100.0 / nullif(blks_hit + blks_read, 0), 2) AS hit_ratio
FROM pg_stat_database
WHERE datname NOT LIKE 'template%';

work_mem怎么定值才不会翻车

work_mem的默认值只有4MB,对现代服务器来说偏保守。如果你的执行计划里频繁出现temp文件,或者sort节点显示Sort Method: external merge而不是quickSort,就说明排序内存不够用了。调整work_mem的目标,就是让绝大多数排序和哈希操作都能在内存中完成。

定值时有一个常用的估算思路:先用公式算出理论上可分配的内存,即(物理内存 - shared_buffers - 系统预留)除以最大并发活跃连接数,再除以单条查询的平均复杂节点数,得出的结果就是work_mem的安全上限。举个例子,16GB内存、shared_buffers占4GB、预留2GB给系统、最大活跃连接50个、平均每条查询2个内存密集节点,那么(16-4-2)*1024/50/2约等于102MB,保守取一半设50MB左右就比较安全。

除了全局设置,更推荐的做法是分级配置。全局的postgresql.conf里保持一个中等值,比如32MB到64MB,然后针对报表类大查询在会话级别动态调大:

-- 全局保持保守值,个别大查询临时调大
SET work_mem = '256MB';
SELECT ... -- 复杂报表查询
RESET work_mem;

-- 或者只给特定角色设置
ALTER ROLE report_user SET work_mem = '256MB';

这种方式既保证了普通查询的内存充足,又避免了全局调大后并发场景下的内存失控。同时记得关注pg_stat_statements里的temp表写入量,用它来定位真正需要大内存的SQL,而不是盲目调参数。

组合调优的实战建议

把两个参数放在一起看,才能形成完整的内存规划。以一台16GB内存、跑混合负载(OLTP为主加少量报表)的服务器为例,一套比较合理的初始配置是:shared_buffers设4GB,effective_cache_size设12GB(这个参数不占内存,只是给优化器的成本估算参考),work_mem设64MB,maintenance_work_mem设512MB给建索引和VACUUM用。上线后持续观察命中率、temp文件和内存峰值,再逐步微调。

最后提醒两个常见误区:一是不要指望调参解决所有性能问题,缺少索引的查询调多少work_mem都救不回来,先用EXPLAIN ANALYZE定位真正的瓶颈;二是修改参数后要观察足够长的周期,最好覆盖业务高峰,因为缓存命中和内存压力都是随负载波动的,只看几分钟的数据很容易误判。调优本质上是个循环过程:观察、假设、调整、验证,参数值只是这个过程的产出,而不是一开始就能算出来的标准答案。

shared_bufferswork_memPostgreSQL调优修改时间:2026-09-05 12:50:41

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260905/50916.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。