
为什么要先建立性能基线
如何让 PostgreSQL 数据库长期稳定,而不是每次变慢后才临时排障?很多团队会把性能问题理解成“加索引、扩内存、调参数”,但生产环境真正需要的是一套可复查的性能基线。基线的作用不是追求某个极限跑分,而是回答三个问题:当前资源还能支撑多少业务增长,哪些指标已经接近风险区间,下一次扩容或迁移应该提前多久准备。本文会把重点放在容量规划、资源边界和日常监控,帮助你把 PostgreSQL 性能调优从一次性操作变成持续管理。
这篇文章与慢查询排障流程不同。慢查询排障通常从某条 SQL 入手,关注执行计划、索引命中和单次请求耗时;性能基线规划则从整个数据库实例入手,关注连接规模、热数据集、缓存命中率、磁盘延迟和业务高峰。两者都重要,但目标不同:前者解决已经暴露的问题,后者减少问题集中爆发的概率。
先把业务负载拆成可量化画像
性能基线的第一步,是把“数据库压力大”拆成具体画像。建议至少记录四类数据:每分钟查询数、写入事务数、活跃连接数和核心表的数据增长速度。比如一个订单系统当前每分钟 1800 次读查询、260 次写入事务,订单表每天新增 80 万行,活跃连接在午间高峰达到 120 个;这些数字比“访问量变大了”更适合用于规划。
可以先用 PostgreSQL(一种开源关系型数据库)内置视图收集连接和事务趋势:
SELECT datname,
numbackends,
xact_commit,
xact_rollback,
blks_read,
blks_hit
FROM pg_stat_database
WHERE datname = current_database();
如果已经启用 pg_stat_statements,还应把总耗时最高的前 20 条 SQL 纳入画像。这里不急着改 SQL,而是先判断负载类型:读多写少、写入密集、报表分析型,还是高并发短事务。不同画像对应的资源瓶颈不同,读多写少更容易受缓存命中率影响,写入密集更依赖 WAL(预写式日志,即 Write-Ahead Logging,数据库用于保证持久性的日志机制)刷盘能力,高并发短事务则要重点看连接池和上下文切换。

用连接规模评估内存和进程压力
PostgreSQL 为每个客户端连接分配独立后端进程,每个连接通常会带来数 MB 到十几 MB 的内存开销。连接数不是越高越好,如果应用把 500 个 Web 连接直接打到数据库,CPU 可能大量消耗在进程调度和锁等待上,而不是实际处理查询。性能基线中应记录三个值:平时活跃连接数、高峰活跃连接数、异常峰值连接数。
对于中小型 Web 应用,可以把 PgBouncer 这类连接池放在应用和数据库之间,把客户端连接与真实数据库连接拆开。一个保守起点是让 default_pool_size 接近 CPU 核心数的 2-4 倍,再观察排队时间和事务耗时。例如 8 核服务器可以先从 16-32 个后端连接开始,而不是直接把 max_connections 拉到 300。
pool_mode = transaction
default_pool_size = 24
max_client_conn = 200
reserve_pool_size = 4
连接池上线后,基线要同时记录两侧指标:应用等待连接的耗时,以及数据库内真实活跃连接数。如果 SQL 本身只执行 40 毫秒,但接口总耗时超过 1 秒,问题可能是连接池排队、事务未及时提交,或应用层持有连接时间过长。把这些数据纳入基线,后续扩容时才知道是应该加数据库资源,还是先修应用连接管理。
内存基线关注热数据集而不是单个参数
很多 PostgreSQL 性能建议会直接给出 shared_buffers 设置为系统内存 25%、effective_cache_size 设置为 50-75% 这类经验值。它们可以作为起点,但不能替代热数据集评估。真正要问的是:业务最常访问的数据和索引有多大,数据库和操作系统缓存能否覆盖这部分热点。
可以用表和索引大小先估算主要对象的体量:
SELECT relname,
pg_size_pretty(pg_total_relation_size(relid)) AS total_size,
pg_size_pretty(pg_relation_size(relid)) AS table_size
FROM pg_catalog.pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC
LIMIT 10;
假设订单表和相关索引总计 38GB,而服务器内存只有 16GB,缓存命中率在高峰期从 99% 降到 94%,就不能只靠调大 work_mem 解决。更合理的动作可能是清理历史数据、拆分冷热表、增加内存,或把报表查询迁移到只读副本。对于运行在 VPS(虚拟专用服务器) 或独立服务器上的数据库,内存基线还应保留 20-30% 给操作系统文件缓存和后台任务,避免峰值时触发 swap。

磁盘 I/O 基线决定写入高峰能否扛住
数据库稳定性很大程度取决于磁盘 I/O。读查询慢可能由缓存不足造成,写入慢则常常和 WAL 刷盘、检查点、随机写延迟有关。性能基线里至少要记录平均读写延迟、95 分位延迟、检查点频率和磁盘队列长度。只看磁盘使用率不足以判断风险,因为 40% 使用率也可能伴随很高的随机写延迟。
在 PostgreSQL 内部,可以关注检查点和缓冲区写入情况:
SELECT checkpoints_timed,
checkpoints_req,
checkpoint_write_time,
buffers_checkpoint,
buffers_backend
FROM pg_stat_bgwriter;
如果 checkpoints_req 增长很快,说明检查点经常被 WAL 空间提前触发,写入高峰可能出现明显抖动。可以评估 max_wal_size、checkpoint_timeout 和 checkpoint_completion_target,但每次只改一个变量,并保留变更前后 24 小时的 I/O 数据。对于订单、日志、消息这类持续写入场景,SSD 或 NVMe 存储的随机写能力往往比 CPU 主频更关键。
把监控阈值写成可执行规则
基线如果只停留在文档里,很快会失效。建议把关键指标写成监控阈值,并按告警级别拆分。例如缓存命中率连续 10 分钟低于 98% 作为观察告警,低于 95% 作为处理告警;活跃连接超过连接池后端连接数的 80% 持续 5 分钟,需要检查应用连接释放;磁盘 95 分位写延迟超过 20 毫秒,则要排查检查点、批量写入或底层存储。
常见的基线指标可以按下面方式整理:
- 查询侧:记录总耗时最高的前 20 条 SQL,单条 SQL 95 分位耗时超过 500 毫秒时进入优化清单。
- 连接侧:高峰活跃连接数长期超过池大小 80% 时,检查连接泄漏、长事务和池化模式。
- 内存侧:缓存命中率低于 98% 且磁盘读延迟上升时,评估热数据集和内存容量。
- 写入侧:检查点提前触发次数持续增加时,复核 WAL 空间、批量任务和存储延迟。
- 增长侧:核心表按周统计容量增速,预计 60 天内触达磁盘 75% 时提前规划清理或扩容。
这些阈值不是固定答案,应该结合业务峰值调整。外贸站、SaaS 后台、论坛和订单系统的高峰模式不同,同一个 500 毫秒 SQL 在后台报表里可能可以接受,在支付回调链路里就需要优先处理。更多服务器侧排查和资源规划方法,可以参考 稳定负载服务器规划指南。
部署环境也要进入基线范围
PostgreSQL 性能基线不只属于数据库本身,还要覆盖运行环境。操作系统层面建议记录内核版本、文件系统、swap 设置、磁盘挂载参数和备份窗口。比如 vm.swappiness 可以设置为 1 或 5,减少数据库内存被换出的概率;透明大页(THP)在部分场景下会带来延迟抖动,生产数据库通常建议关闭后再观察。
如果数据库和 Web 应用部署在同一台服务器上,还要把 Web 进程、缓存服务、定时任务纳入容量规划。一个常见问题是白天数据库表现正常,凌晨备份或报表任务启动后,磁盘 I/O 被抢占,第二天用户看到的是页面打开慢。建议把备份、统计任务和索引维护放进基线记录,明确它们的执行时间、持续时长和资源消耗。
在选择承载 PostgreSQL 的基础设施时,建议优先确认三点:是否有稳定的 SSD/NVMe 存储,是否方便按需扩展内存,是否能提供清晰的网络和硬件监控。Hostease 的 服务器栏目中有不少部署和运维参考,你可以结合业务负载选择合适的独服([独立服务器](https://cn.hostease.com/dedicated-server/))或 [VPS](https://cn.hostease.com/vps/)([虚拟专用服务器](https://cn.hostease.com/vps/))方案。
总结:基线比临时调参更可靠
总结来说,PostgreSQL 性能基线规划的价值,是把数据库稳定性从“凭经验感觉”变成“用数据判断”。建议先建立业务负载画像,再依次确认连接规模、热数据集、磁盘 I/O、监控阈值和部署环境。完成第一版基线后,可以每周复查一次容量增长,每月复盘一次慢查询和告警记录。如果你需要为即将增长的业务提前准备数据库环境,可以考虑先用小规模压测验证资源边界,再决定是优化现有配置、拆分读写负载,还是升级到更合适的服务器方案。