Python SQLAlchemy:测试关系是否存在,而不实际加载它

Python SQLAlchemy:测试关系是否存在,而不实际加载它,python,performance,sqlalchemy,Python,Performance,Sqlalchemy,我不确定这是否可能,但我在SQLite中使用了SQLAlchemy的层次结构类型结构。 在我的层次结构中,我想向用户指出父级有子级,而不需要加载所有子级。 我知道SQLAlchemy使用延迟加载,但是当我访问relationship属性时,整个列表都被加载了。由于父级可以有数千个子级,因此仅测试子级就相当大的性能开销!=没有 目前,该关系定义如下: children = relationship('child', cascade='all',

我不确定这是否可能,但我在SQLite中使用了SQLAlchemy的层次结构类型结构。 在我的层次结构中,我想向用户指出父级有子级,而不需要加载所有子级。 我知道SQLAlchemy使用延迟加载,但是当我访问relationship属性时,整个列表都被加载了。由于父级可以有数千个子级,因此仅测试子级就相当大的性能开销!=没有

目前,该关系定义如下:

children = relationship('child',
                        cascade='all',
                        backref=backref('parent'),
                        )
我目前使用以下方法测试儿童:

qry = session.query(parenttable).all()

for parent in qry:
    if parent.children != None:
        childrenindication = [{'Name': '...'}]
    else:
        childrenindication = []

    hierarchylist.append({
                'Name': parent.name,
                'Children': childrenindication
                })

如果有一种性能更友好的方法可以做到这一点,那就太好了。

假设一个示例模型:

class Parent(Base):
    __tablename__ = 'parent'

    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False)

    children = relationship("Child", cascade="all", backref="parent")


class Child(Base):
    __tablename__ = 'child'

    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False)
    parent_id = Column(ForeignKey(Parent.id))
下面列出了几个选项,其中第一个选项是对您的问题最直接的回答:

选项1:使用关系。任何…-可能是最快的 选项2:使用子查询获取子项的数量 选项3:如果父表没有子查询,则获取子查询数良好
假设样本模型:

class Parent(Base):
    __tablename__ = 'parent'

    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False)

    children = relationship("Child", cascade="all", backref="parent")


class Child(Base):
    __tablename__ = 'child'

    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False)
    parent_id = Column(ForeignKey(Parent.id))
下面列出了几个选项,其中第一个选项是对您的问题最直接的回答:

选项1:使用关系。任何…-可能是最快的 选项2:使用子查询获取子项的数量 选项3:如果父表没有子查询,则获取子查询数良好
但是如果有子项,在填充列表时仍然需要加载它们。因此,看起来您不会真正节省任何性能。或者我遗漏了什么?我想测试孩子们是否存在,如果可能的话,根本不加载他们。在列表中,我只添加了一个子项的指示,即在本例中,一个名为children的非空列表。可能类似于搜索父项的子项的查询,但从那时起,关系在第一时间就中断了,无论其中有多少子项。好的,现在我可以从代码中看到,您实际上没有加载它…但是如果有子项,您仍然需要在填充列表时加载它们。因此,看起来您不会真正节省任何性能。或者我遗漏了什么?我想测试孩子们是否存在,如果可能的话,根本不加载他们。在列表中,我只添加了一个子项的指示,即在本例中,一个名为children的非空列表。可能类似于搜索父项的子项的查询,但从那时起,关系在第一时间就中断了,无论其中有多少子项。好的,现在我可以从代码中看到,您实际上没有加载它…嗨,谢谢您的回答,但是我无法让它们中的任何一个正常工作。当我使用any时,我会得到'AttributeError:'InstrumentedList'对象没有'any'属性。对于其他选项,我使用了我在中列出的层次结构,它似乎不太适合它们。但是,我阅读了有关索引的内容,并在ForeignKey中添加了'index=True'。它给了我巨大的性能提升,几乎不需要任何其他东西。我应该加上这个作为答案吗?请加上这个作为答案。尽管如此,如果您不需要加载数据,您也不应该这样做,即使它比以前更快:它仍然使用CPU,并且会为所有子对象实例使用更多内存。您好,谢谢您的回答,但我无法让它们中的任何一个正常工作。当我使用any时,我会得到'AttributeError:'InstrumentedList'对象没有'any'属性。对于其他选项,我使用了我在中列出的层次结构,它似乎不太适合它们。但是,我阅读了有关索引的内容,并在ForeignKey中添加了'index=True'。它给了我巨大的性能提升,几乎不需要任何其他东西。我应该加上这个作为答案吗?请加上这个作为答案。尽管如此,如果您不需要加载数据,也不应该加载,即使加载速度比以前快:它仍然使用CPU,并且将为所有这些子对象实例使用更多内存。
# @note: returns None instead of 0 for parent with no children
from sqlalchemy import func
subq = (
    session.query(Child.parent_id, func.count(Child.id).label("num_children"))
    .group_by(Child.parent_id)
    .subquery()
)
q = (session
     .query(Parent, subq.c.num_children)
     .outerjoin(subq, Parent.id == subq.c.parent_id)
     )
for parent, has_children in q.all():
    print(parent, has_children)
# not have many columns
from sqlalchemy import func
q = (session
     .query(Parent, func.count(Child.id).label("num_children"))
     .outerjoin(Child, Parent.children)
     .group_by(Parent)
     )
for parent, has_children in q.all():
    print(parent, has_children)