asyncpg比psycopg2快,关键在于其绕过文本协议、直接实现二进制协议解析,并默认启用预编译语句缓存;实测同构简单查询单连接吞吐可达psycopg2的3–5倍,但需满足查询模式稳定、不阻塞事件循环、连接池配置合理等前提。

asyncpg 能显著提升 PostgreSQL 吞吐,但直接替换 psycopg2 不等于自动变快——关键在连接复用、查询结构和事件循环协同。
为什么 asyncpg 比 psycopg2 快?不是“异步”本身,而是协议层优化
asyncpg 绕过 PostgreSQL 的文本协议,直接实现二进制协议解析,省掉大量字符串转换和类型映射开销;它还默认启用 prepared statement 缓存,而 psycopg2 的 cursor.execute() 每次都走完整解析流程。实测同构简单查询,asyncpg 单连接吞吐常是 psycopg2 的 3–5 倍。
但这个优势只在以下情况成立:
- 查询模式稳定(参数类型/数量不变),才能命中 prepared statement 缓存
- 不混用阻塞操作(如同步日志写入、
time.sleep()、未 await 的协程)阻塞事件循环 - 连接池大小与并发请求数匹配,而非盲目调大
必须改写的三处核心代码模式
asyncpg 不是“async psycopg2”,很多惯用写法会出错或退化性能:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
-
conn.fetchrow()替代cursor.fetchone(),但注意它返回Record对象,不是 tuple —— 若旧代码依赖下标取值(如row[0]),需改用字段名row["id"]或调用row.values() - 事务块必须显式用
async with conn.transaction():,不能靠conn.commit()手动提交;漏写会导致连接卡在事务中,连接池迅速耗尽 - 批量插入别用
conn.executemany()(已废弃),改用conn.executemany("INSERT ...", data_list)或更优的conn.copy_records_to_table()(对万级以上数据快 3–10 倍)
连接池配置不当比不用 asyncpg 更伤吞吐
asyncpg 的 create_pool() 默认 min_size=10、max_size=10,看似合理,但实际常导致连接争抢或闲置:
- Web 服务(如 FastAPI)建议设
min_size=5、max_size=20,并配合max_queries=5000(避免长连接内存泄漏) - 若应用有突发短时高并发(如定时任务拉取 1000 条记录),
max_inactive_connection_lifetime=180.0可防连接僵死 - 切勿在每次请求里
await asyncpg.create_pool()—— 这会创建新池,彻底失去复用价值;池应全局单例初始化
最容易被忽略的兼容性陷阱
asyncpg 对 PostgreSQL 类型处理更严格,几个高频翻车点:
-
jsonb字段返回的是str,不是 Python dict —— 必须手动json.loads(row["data"]),而psycopg2默认做这步 -
timestamp with time zone返回datetime.datetime对象,但其tzinfo是asyncpg.types.DateTimeZone,不能直接传给pydantic或pd.Timestamp;需先转为 UTC:row["ts"].astimezone(timezone.utc) - 空字符串
''插入TEXT字段正常,但插入JSONB会报invalid input syntax for type json—— asyncpg 不做隐式空值转换
这些细节不处理,程序可能跑几天才在某个边缘 case 崩溃,且错误堆栈不提示根源。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










