DEBUG.WIKI
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS
IPPeak:从目标地区访问网页,住宅代理、SEO 监测、广告验证
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国

asyncpg 0.28 关闭缓存后仍报 unnamed prepared statement does not exist

核对0.28匿名预备语句路径、0.29正式修复与池化版本,区分缓存设置和扩展查询协议。

asyncpg 已设置 statement_cache_size=0,经过 PgBouncer 事务池查询时,仍报 InvalidSQLStatementNameError: unnamed prepared statement does not exist。如果使用的是 0.28.0,并且路径中交替出现显式 prepare 和普通 fetch,要检查这一版在匿名预备语句上的兼容问题,不能只把缓存参数再设一次。

这条路径见于 asyncpg 0.28.0、Python 3.10、PostgreSQL 14 和 PgBouncer transaction 模式。PgBouncer 的具体旧版本未确定;以下不把这个组合推广到所有池化服务,也不把后续具名语句重复错误当成同一个故障。

缓存为零,不代表连接不再发送 Parse

asyncpg 的普通参数查询依赖 PostgreSQL 扩展查询协议,匿名预备语句也是其中一部分。statement_cache_size=0 关闭的是普通语句缓存和复用,不会把所有查询改为不准备语句的路径。代码显式调用 conn.prepare() 时,也不能期待这个参数阻止 prepare。

受影响的调用顺序可以是:显式准备一个有名称的语句并读取,释放该对象,随后调用普通 fetchrow()。报错出现在后一个匿名语句,位置与先前 prepare 分开。在旧的事务池交互中,准备、描述、绑定执行之间的后端状态不能按驱动当时的假设持续保留。

因此,删除 prepare、长期保留对象或关闭连接存活检查,都可能改变症状,却不足以说明查询和连接生命周期已经正确。先保存完整第一条异常、实际版本、池化模式及调用顺序,区分匿名语句不存在、具名语句重复和 DDL 后计划失效。

受影响版本,优先核对正式修复

asyncpg 0.29.0 的正式修复包含关闭缓存时更保守地处理匿名预备语句:在相应路径中不依赖此前的准备状态,绑定执行前重新发送 Parse。它增加了协议工作,不能据此承诺没有性能成本或所有池化问题都会消失。

若当前仍是受影响的 0.28 系列,先按项目兼容要求评估升级到含修复的正式版本,在隔离环境覆盖这条调用顺序、连接复用和事务边界。升级前保存依赖锁文件及部署版本,核对 Python、SQLAlchemy 或其他封装层的兼容范围;不要只改一个版本号就同时替换池化架构。

直接使用 asyncpg 时,已有连接可以用明确的事务上下文约束一段数据库操作。下面仅展示受控读取的范围,conn 必须是按现有认证、TLS 和池化配置取得的连接:

async with conn.transaction():
    row = await conn.fetchrow("SELECT 1 AS connection_check")

这会开启并结束一个事务,并不是没有影响的连接参数。需要评估事务长度、连接占用以及实际失败路径是否也被覆盖。不能在整个请求生命周期中长时间占着事务,也不能把这个读取片段宣称为所有 prepare 使用方式的修复。

当前 PgBouncer 要按版本和语句类型判断

PgBouncer 1.21.0 起,在 max_prepared_statements 为非零时支持跟踪协议级具名预备语句。较新的配置文档默认值为 200,但实际部署可能覆盖它;应核对运行实例的版本和有效配置,不能从旧错误提示得出“事务池始终不支持预备语句”的结论。

这项支持针对协议级具名语句。SQL 层的 PREPARE、EXECUTE 不会因此自动获得同样的跟踪改写,匿名语句的历史驱动问题也不能只靠这个设置解释。不要盲目修改全局重置查询或清理所有会话的预备状态。

SQLAlchemy 的 asyncpg 方言还可能使用自己的 prepared_statement_cache_size,它与直接 asyncpg 的 statement_cache_size 不同。如果错误实际发生在迁移后的旧计划,检查DDL 后 asyncpg 缓存与失败事务的处理,不要沿用这里的匿名语句诊断。

验收应使用应用原来的获准入口,覆盖首次查询、后续连接复用、显式事务和实际 prepare/fetch 组合,确认不再出现同一匿名语句错误,并核对事务结果。若失败改为具名重复、类型缓存或其他池化服务异常,保留新的完整错误重新判断;依赖回退只恢复软件版本,不撤销已经提交的业务修改。