Pydantic触发冗余SQL查询:已预加载字段仍重复查询
问题解决:Pydantic model_validate触发SQLAlchemy重复查询
核心原因
你当前的代码顺序是先修改read字段并提交数据库会话,再执行model_validate转换为Pydantic模型。会话提交后,SQLAlchemy的ORM对象会进入detached状态,此时访问预加载的关联字段(如portfolio_files)或延迟加载字段(如created_at)时,ORM会尝试重新发起SQL查询来获取数据,即使这些数据已经预加载到内存中。
解决方案
调整代码执行顺序,在数据库会话提交前完成Pydantic模型的转换,确保ORM对象处于会话活跃状态(attached),此时访问预加载字段会直接从内存/会话缓存中读取,不会触发额外查询。
同时,修正查询结果的获取方式,使用scalar_one()替代unique()来确保获取单个ORM实例(unique()返回的是去重结果集,可能存在隐式问题)。
修改后的代码示例
路由函数调整
@router.get( '/{portfolio_id}', summary='Get portfolio detail', response_model=PortfolioFullSchema, status_code=status.HTTP_200_OK, ) async def get_portfolio( portfolio_id: int, auth_user: OptionalAuthUser, db: DbDependency, ): """get user portfolio route""" builder = PortfolioQueryBuilder( auth_user_username=auth_user and auth_user.username, # type: ignore[arg-type] portfolio_id=portfolio_id, ) # 修正:用scalar_one()获取单个ORM实例 portfolio: Portfolio = db.execute(await builder.full()).scalar_one() print(portfolio.portfolio_files) # [<models.portfolio.PortfolioFile object at 0x7f5f0a5d8a50>] print(portfolio.created_at) # 2024-05-22 09:20:11.749022+00:00 portfolio.simple_appreciates_count, portfolio.senior_appreciates_count = 4, 5 # type: ignore[attr-defined] # 先完成Pydantic模型转换,此时会话仍活跃 portfolio_schema = PortfolioFullSchema.model_validate(portfolio, from_attributes=True) # 再执行修改和提交操作 portfolio.read += 1 db.add(portfolio) db.commit() return portfolio_schema
额外验证点
如果调整顺序后仍有问题,可以检查以下两点:
- 确认
Portfolio模型中portfolio_files关联的lazy配置是否为默认的select,joinedload会覆盖该配置完成预加载,无需额外修改,但要确保没有其他逻辑覆盖预加载选项。 - 打印
portfolio.__dict__查看created_at和_portfolio_files(SQLAlchemy内部存储关联的属性)是否存在值,确认预加载确实生效。
内容的提问来源于stack exchange,提问作者Miradil Zeynalli
相关产品推荐
相关产品推荐

