直接用 pymysql.connect() 会拖慢服务,因其每次调用都需 tcp 握手、mysql 认证和会话初始化,耗时 20–100ms;连接池是高并发下避免连接数爆炸和延迟毛刺的刚需。

为什么直接用 pymysql.connect() 会拖慢服务?
每次请求都调用 pymysql.connect() 建连,本质是 TCP 握手 + MySQL 认证 + 初始化会话状态,耗时通常在 20–100ms(尤其跨机房)。连接池不是“锦上添花”,而是高并发下避免连接数爆炸和延迟毛刺的刚需。
常见错误现象:Too many connections 报错、响应 P99 突然跳高、数据库连接数监控持续贴顶。
- 不要在每次查询前手动
connect()+close() - 不要把连接对象存在全局变量或类实例里长期持有(容易被复用但未重置状态,引发事务/字符集污染)
- 短连接模式下,
autocommit=False的连接若没显式rollback()或commit(),归还到池中后可能残留未提交事务,下次借出时执行execute()会报MySQLdb._exceptions.OperationalError: (2014, "Commands out of sync")
用 DBUtils.PooledDB 搭最简可用池
DBUtils 是老牌稳定方案,不依赖 ORM,轻量且对 PyMySQL/MySQLdb 都兼容。它不做连接健康检测,靠“借出时验证 + 归还时清理”兜底,适合内网稳定环境。
关键参数含义:
-
mincached=5:空闲时至少保留 5 个连接,避免冷启动抖动 -
maxcached=10:最多缓存 10 个空闲连接,防内存浪费 -
maxconnections=20:整个池最大允许创建 20 个连接(超限会阻塞或抛异常,按需设) -
ping=1:借出前执行SELECT 1检测连接是否存活(值为 1 表示检测,0 表示跳过)
示例:
from DBUtils.PooledDB import PooledDB
import pymysql
<p>pool = PooledDB(
creator=pymysql,
mincached=5,
maxcached=10,
maxconnections=20,
ping=1,
host='10.0.1.100',
port=3306,
user='app',
password='xxx',
database='mydb',
charset='utf8mb4'
)</p><h1>使用时:</h1><p>conn = pool.connection() # 借连接(非新建)
cursor = conn.cursor()
cursor.execute("SELECT id FROM users WHERE status=%s", ('active',))
result = cursor.fetchall()
cursor.close()
conn.close() # 归还给池,不是断开物理连接
</p>
用 SQLAlchemy 的 create_engine 更省心?
如果你项目已用 SQLAlchemy,直接复用其内置连接池更安全——它自动处理连接失效重试、空闲连接回收(pool_recycle)、以及事务上下文绑定。
必须设的关键参数:
-
pool_size=10:默认 5,建议设为预估峰值并发的 1.2–1.5 倍 -
max_overflow=10:超出pool_size后允许临时创建的额外连接数(防止突发流量打穿) -
pool_recycle=3600:强制回收超过 1 小时的连接(防 MySQL server_timeout 导致的Lost connection during query) -
pool_pre_ping=True:比ping=1更彻底,借出前先发PING包并验证响应,适合网络不稳定场景
注意:echo=True 仅调试用,线上必须关,否则日志 I/O 会吃掉大量性能。
连接池没生效?先查这三件事
很多“用了池但延迟没降”的问题,其实根本没走池逻辑。
- 检查代码里是否还有散落的
pymysql.connect()调用(grep -r "pymysql.connect" .) - 确认
conn.close()是否真被调用——用 context manager 最保险:with pool.connection() as conn: - 观察 MySQL 的
SHOW STATUS LIKE 'Threads_connected';:如果数值长期等于你设的maxconnections,说明池被撑满,要么调大池上限,要么查是否有连接泄漏(比如没 close、异常跳过 close)
池本身不解决慢查询,如果单次查询要 500ms,复用连接也救不了。先用 slow_query_log 定位 SQL,再谈连接复用。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











