You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何asyncpg连接池比单连接运行速度慢2倍?

问题分析:连接池版本比单连接慢一倍的原因

你的测试结果里连接池版本更慢,主要是实现细节和测试场景的问题,而非数据库端的问题,具体原因如下:

1. 每次查询重复执行连接获取/释放的额外开销

单连接版本复用同一个连接完成所有100次查询,没有额外的连接调度开销;而连接池版本的fetch_all方法每次都执行:

async with pool.acquire() as conn:

这意味着每次查询都要从连接池中申请连接、用完后归还,这个过程包含连接池内部的锁竞争、连接状态校验等操作,串行执行100次的话,这些额外步骤的开销会被累积放大。

2. 查询结果的格式转换开销

连接池版本的fetch_all把查询结果从asyncpg.Record强制转成了dict:

return [dict(row) for row in await conn.fetch(query)]

而单连接版本直接返回asyncpg.Record对象。dict(row)的转换是纯CPU开销,如果user表字段较多、结果集较大,100次转换的累积开销非常可观。

3. 测试场景未匹配连接池的优势

连接池的核心价值是高并发场景下复用连接、避免频繁创建销毁连接的开销,而你的测试是串行执行100次查询:单连接串行本来就是最优模式(没有连接创建/切换开销),连接池在这种场景下反而会因为额外的调度逻辑拖慢速度。


改进建议

1. 调整测试逻辑做公平对比

如果要公平对比,连接池版本也应该复用单个连接执行所有查询,和单连接的逻辑对齐:

pg_conn = PostgresConnection()
pool = await pg_conn.get_pool()
async with pool.acquire() as conn:
    for i in range(100):
        rows = await conn.fetch('SELECT * FROM "user"')
        # 按需转换为dict

这样就能消除每次获取/释放连接的开销,测试结果会和单连接版本接近。

2. 去掉不必要的结果转换

如果业务不需要dict格式,直接返回asyncpg.Record即可,避免转换开销:

async def fetch_all(self, query: str) -> list[asyncpg.Record | None]:
    pool = await self.get_pool()
    async with pool.acquire() as conn:
        return await conn.fetch(query)

3. 用并发场景测试连接池的真实优势

连接池的优势在并发场景才能体现,比如用asyncio.gather同时执行多个查询:

import asyncio

pg_conn = PostgresConnection()
tasks = [pg_conn.fetch_all('SELECT * FROM "user"') for _ in range(100)]
await asyncio.gather(*tasks)

这种场景下,连接池可以同时复用多个连接处理请求,总耗时会远低于单连接串行的5秒。


内容的提问来源于stack exchange,提问作者Maksim Burtsev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 03:32:46