asyncpg性能最强因直连二进制协议,生产必须用create_pool()连接池而非connect();min_size设为平均并发1.2–1.5倍,max_size不超数据库max_connections的70%,需设max_inactive_time=300秒防泄漏。
是目前 Python 生态中性能最强的异步 PostgreSQL 驱动,它不走 DB-API 兼容层、不依赖 psycopg2,而是直接实现 PostgreSQL 二进制协议,因此在高并发读写场景下优势明显。如果你的应用正面临连接阻塞、QPS 上不去、或
在 asyncio 环境中被迫用线程池兜底的窘境,换用
并合理调优,通常能带来 3–10 倍的吞吐提升。
为什么不能直接用
处理并发请求
单次
创建的是独占连接,无法复用;在 Web 请求中每来一个请求就新建连接,很快会耗尽数据库连接数(PostgreSQL 默认
),并触发
。更严重的是,TCP 握手 + SSL + 认证开销会让首字节延迟飙升。
正确做法是全程使用连接池:
是唯一推荐的生产级入口,它内部管理连接生命周期、自动重连、支持连接预热
建议设为应用平均并发请求数的 1.2–1.5 倍(例如常驻 8 个活跃连接,设
)
不宜盲目拉高——超过数据库
的 70% 就可能引发拒绝连接;建议先压测再定(常见值:15–30)
务必设置
(单位秒),否则空闲连接长期不释放,会卡住连接池回收逻辑
批量插入时为何有时比循环
还慢
这不是
的 bug,而是误用了批量接口的典型表现。当传入的
是生成器(
)、或元素数量极少(
)、或字段类型混杂(比如混合了
和
)时,
内部的参数序列化反而增加 CPU 开销。
立即学习
“
Python免费学习笔记(深入)
”;
实战建议:
Python 3.14.3
微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。
下载
确保
是 list 或 tuple,且长度 ≥ 10;小于该阈值直接用
+
拼接更稳
避免在
中混用
和
字段——不同编解码路径会触发多次缓存 miss
若需动态列名(如 ETL 场景),不要强行塞进
,改用事务包裹多个
并显式
事务里用
后再
报
这是 PostgreSQL 协议层的硬性限制:一旦事务中某条语句出错(哪怕只是
查不到数据),整个事务就进入“failed”状态,后续任何非
操作都会被拒绝。
常见踩坑点:
返回
本身不是错误,但若紧接着执行
而没做
判断,逻辑上可能漏掉分支,但不会报这个错
真正触发该异常的是类似
因主键冲突抛出
后,还继续发其他
解决方式只有两个:
显式捕获异常后
,或改用
隔离子操作(
→ 出错时
)
缓存语句(
)设多大才合适
默认开启语句缓存(
),它把已解析的 SQL 文本 + 类型映射存内存里,避免重复解析。但缓存不是越大越好。
关键判断依据:
如果应用中 90% 的查询来自固定模板(如
),保持默认 100 完全够用
若大量使用动态 SQL(比如拼接
字段、不定长
),缓存命中率会暴跌,此时设为
反而降低内存抖动
注意:缓存大小只影响客户端,不影响 PostgreSQL 服务端的 prepared statement;
不自动使用服务端预编译,除非你手动调用
实际部署时最容易被忽略的是连接池和事务的生命周期绑定关系:连接池里的每个连接都维护独立的事务状态,
得到的连接若未在作用域内完成
或
,该连接会被标记为“不可复用”,直到超时后强制关闭。这意味着——事务必须在
块内结束,不能跨
拆开。
asyncpgpsycopg2asyncpgasyncpg.connect()asyncpg.connect()max_connections=100asyncpg.exceptions.TooManyConnectionsErrorasyncpg.create_pool()min_sizemin_size=10max_sizemax_connectionsmax_inactive_time=300executemany()execute()asyncpgdatageneratorlen(data) < 5Nonedatetimeexecutemany()dataexecute()VALUES ($1,$2),($3,$4)executemany()jsonbyteaexecutemany()execute()await conn.executemany(...)fetch()execute()asyncpg.exceptions.InFailedSQLTransactionWHERE id = -1ROLLBACKconn.fetchrow("SELECT ...")Noneconn.execute("UPDATE ...")if row is not None:conn.execute("INSERT INTO t(pk) VALUES (1)")UniqueViolationErrorexecute()await tx.rollback()SAVEPOINTawait tx.execute("SAVEPOINT sp1")await tx.execute("ROLLBACK TO sp1")statement_cache_sizeasyncpgstatement_cache_size=100"SELECT * FROM users WHERE status = $1"ORDER BYIN ($1, $2, ..., $N)0asyncpgconn.prepare()acquire()commit()rollback()async with pool.acquire() as conn:await