数据库连接池大小设多少合适?
更新时间:2026-09-18。问题驱动短答页。最常见的错误是「连接池越大越好」,实际往往相反。
一句话回答
连接数不是越大越好:对 CPU 密集型查询,活跃连接数接近「CPU 核心数的几倍」时吞吐最高、延迟最低,盲目开到几百反而因上下文切换和锁竞争变慢。常用起点是 HikariCP 官方公式 连接数 = 核心数 × 2 + 有效磁盘数,再压测微调。
为什么连接太多反而慢
数据库执行查询时真正干活的是 CPU 和磁盘。几十个连接同时跑,就有几十个线程抢同一批 CPU 核心,带来:
- 频繁上下文切换,CPU 大量耗在调度而非计算;
- 行锁/latch 竞争加剧,等待变多;
- 每个连接占内存(PG 每连接一个进程,开销尤其大)。
经典实测(PostgreSQL 官方):在同样硬件上,连接数从 200 降到 ~20,吞吐量反而上升、延迟下降。
推荐起点
| 数据库/场景 | 活跃连接建议 |
|---|---|
| PostgreSQL(每连接一进程,开销大) | 核心数 × 2 + 有效磁盘数,例如 4 核 SSD ≈ 9~10 |
| MySQL(线程模型,略轻) | 核心数的 2~4 倍起步,例如 4 核 ≈ 8~16 |
| 纯内存/超高 IOPS 存储 | 可适当上调,但仍以压测为准 |
| 多应用实例 | 用 所有实例连接数之和 对数据库核数算,不是单实例 |
关键区分:连接池里可以有一些空闲连接(minimumIdle),但同时活跃执行的连接数才是上面公式约束的对象。
HikariCP 配置示例
yaml
spring:
datasource:
hikari:
maximum-pool-size: 10 # 4 核 PG 的起点,而非 100
minimum-idle: 10 # 固定池时建议与 max 相同,避免频繁建连
connection-timeout: 3000
max-lifetime: 1800000 # 小于数据库/中间件的 wait_timeout
idle-timeout: 600000- 固定负载建议
minimumIdle = maximumPoolSize,避免连接忽建忽关。 - 微服务实例多时,每实例池要按「实例数 × 单池」摊薄,否则总连接打爆数据库——这时上 PgBouncer 事务级池化,让大量客户端连接复用到少量后端连接,见 PostgreSQL 连接池与 PgBouncer。
怎么定到精确值
- 用 Little 定律估算:
活跃连接 ≈ 峰值 QPS × 平均 SQL 耗时(秒),得到下限。 - 从公式起点取值,用压测逐步增加,观察数据库 CPU、锁等待和应用 RT 的拐点。
- 选「吞吐最高且 P99 延迟最低」的那个点,通常远小于直觉值。
坑
- 把线程数当连接数:Web 线程池可以有几百,但数据库连接池不必跟它一样大,多余请求排队等连接反而是保护。
- 多实例只算单台:10 个实例各配 50 = 500 连接,必须汇总评估。
- 连接泄漏(借了不还):开
leak-detection-threshold排查未关闭的连接。 - 一套参数走天下:读写库、报表库负载不同,要分别配置。
完整参数与连接数公式见 连接池调优:HikariCP 参数与连接数公式;PG 高并发连接治理见 PgBouncer 事务级复用。
总结
数据库连接池不是越大越好,活跃连接数贴近「核心数×2+磁盘数」(PG)或核心数 2~4 倍(MySQL)时吞吐和延迟最优,过多连接只会增加上下文切换、锁竞争和每连接内存;HikariCP 固定负载建议 minimumIdle 等于 maximumPoolSize、maxLifetime 小于数据库超时,微服务多实例要把各实例连接数汇总计算、超量时用 PgBouncer 事务级复用兜底,最终用 Little 定律估下限、压测找 RT 拐点定精确值。