SQLAlchemy渴望加载多个关系

wen*_*ong 7 python mysql sql sqlalchemy

SQLAlchemy支持关系的急切加载,它基本上是一个JOIN声明.但是,如果模型具有两个或更多关系,则它可能是一个非常大的连接.例如,

class Product(Base):
    __tablename__ = 'product'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(255), nullable=False)
    orders = relationship('Order', backref='product', cascade='all')
    tags = relationship('Tag', secondary=product_tag_map)

class Order(Base):
    __tablename__ = 'order'
    id = Column(Integer, primary_key=True, autoincrement=True)
    date = Column(TIMESTAMP, default=datetime.now())

class Tag(Base):
    __tablename__ = 'tag'
    id = Column(Integer, primary_key=True, autoincrement=True)
    tag_type = Column(String(255), nullable=False)
    tag_value = Column(String(255), nullable=False)

q = session.query(Product).join(User.addresses)\
    .options(joinedload(Product.orders))\
    .options(joinedload(Product.tags)).all()
Run Code Online (Sandbox Code Playgroud)

该查询的性能实在是太差了,因为JOINOrderTag会产生一个巨大的表.但是这里OrderTag没有关系,所以他们不应该这样JOIN.它应该是两个独立的查询.并且因为会话具有一定程度的缓存,所以我将查询更改为此.

session.query(Product).join(Product.order) \
    .options(joinedload(Product.tags)).all()

q = session.query(Product).join(User.addresses) \
    .options(joinedload(Product.cases)).all()
Run Code Online (Sandbox Code Playgroud)

这次表现要好得多.但是,我不相信这是正确的.我不确定会话结束时标签的缓存是否会过期.

请让我知道这种查询的适当方式.谢谢!

uni*_*rio 11

对于一对多或多对多的关系subqueryload,出于性能原因,通常会更好地使用它:

session.query(Product).join(User.addresses)\
    .options(subqueryload(Product.orders),\
             subqueryload(Product.tags)).all()
Run Code Online (Sandbox Code Playgroud)

SELECT会对每个orders和发出单独的查询tags.

  • @heplat重点是多个查询比具有连接的单个查询更有效.不,你不可能拥有两全其美,因为SQL不会那样工作. (6认同)