【问题标题】:SQLAlchemy eager loading multiple relationshipsSQLAlchemy 急切加载多个关系
【发布时间】:2016-04-25 11:51:24
【问题描述】:

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()

这个查询的性能真的很差,因为OrderTagJOIN会生成一个巨大的表。但是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()

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

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

【问题讨论】:

    标签: python mysql sql sqlalchemy


    【解决方案1】:

    对于一对多或多对多关系,出于性能原因,(通常)最好使用subqueryload

    session.query(Product).join(User.addresses)\
        .options(subqueryload(Product.orders),\
                 subqueryload(Product.tags)).all()
    

    这会针对orderstags 分别发出SELECT 查询。

    【讨论】:

    • 有没有办法做到不发出多个查询?这似乎会增加开销。
    • @heplat 重点是多个查询比单个查询更有效。不,你不能两全其美,因为 SQL 不是这样工作的。
    猜你喜欢
    • 1970-01-01
    • 2014-02-24
    • 1970-01-01
    • 2014-10-13
    • 2018-05-15
    • 1970-01-01
    • 2021-04-28
    • 2021-12-01
    • 1970-01-01
    相关资源
    最近更新 更多