为何未用joinedload仍可访问关联对象?额外查询何时触发?
问题描述
以下是一段SQLAlchemy代码:
class Items(Base): tag_id = Column(Integer, ForeignKey(Tag.id, ondelete='CASCADE'), index=True) ... tag = relationship('Tag', back_populates='items') query = Select(Items) cursor = await db_session.execute(query) items = cursor.scalars().all() print(items[0].tag.id) # 123
上述代码中未使用joinedload却能正常访问Items关联的Tag对象id属性,请问这一现象的原因是什么?针对关联表的额外查询会在何时执行?
解答
1. 无需joinedload即可访问tag.id的原因
因为Items类中已经定义了tag_id这个外键字段,执行Select(Items)查询时,该字段的值已经被加载到Items实例里。SQLAlchemy有个优化逻辑:当访问关联对象tag的主键id时,会直接复用当前Items实例已有的tag_id值,完全不需要去查询Tag表。
简单来说,这里的tag.id本质上就是items[0].tag_id的映射,SQLAlchemy帮你省略了重复查询的步骤。
2. 关联表额外查询的触发时机
只有当你访问Tag对象的非主键属性时,才会触发额外的SELECT查询。比如执行print(items[0].tag.name)时,SQLAlchemy发现Tag对象的name属性未被加载,就会自动执行一条针对Tag表的查询(SELECT * FROM tag WHERE id = ?),获取完整的Tag记录。
这是SQLAlchemy默认的**延迟加载(lazy loading)**行为,默认情况下relationship的lazy参数为select,只会在首次访问关联对象的非主键属性时触发查询。
内容的提问来源于stack exchange,提问作者Slad
相关产品推荐
相关产品推荐

