Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/345.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/37.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python SQLAlchemy多对多性能_Python_Sql_Sqlalchemy - Fatal编程技术网

Python SQLAlchemy多对多性能

Python SQLAlchemy多对多性能,python,sql,sqlalchemy,Python,Sql,Sqlalchemy,我与多对多关联有一个数据库关系,但关联表本身包含许多需要访问的属性,因此我创建了三个类: class User(Base): id = Column(Integer, primary_key=True) attempts = relationship("UserAttempt", backref="user", lazy="subquery") class Challenge(Base): id = Column(Integer, primary_key=True)

我与多对多关联有一个数据库关系,但关联表本身包含许多需要访问的属性,因此我创建了三个类:

class User(Base):
    id = Column(Integer, primary_key=True)
    attempts = relationship("UserAttempt", backref="user", lazy="subquery")

class Challenge(Base):
    id = Column(Integer, primary_key=True)
    attempts = relationship("UserAttempt", backref="challenge", lazy='subquery')

class UserAttempt(Base):
    challenge_id = Column(Integer, ForeignKey('challenge.id'), primary_key=True)
    user_id = Column(Integer, ForeignKey('user.id'), primary_key=True)
当然,这是一个简化的例子,我省略了需要访问的其他属性。这里的目的是,每个用户都可以尝试任意数量的挑战,因此UserAttention表描述了一个特定用户处理一个挑战

现在的问题是:当我查询所有用户,然后查看每次尝试时,我完全没有问题。但是,当我看到这一尝试的挑战时,它在许多子查询中爆炸。当然,这对性能不利

实际上,我想从SQLAlchemy中得到的是一次解决所有或所有相关的挑战,然后将其与相关的尝试联系起来。如果所有的挑战都被拉出来,或者只是在以后才有实际关联,这并不是什么大问题,因为挑战的数量仅在100-500之间

我现在的解决方案其实不是很优雅:我将所有相关的尝试、挑战和用户分别拉出来,然后手动关联:循环所有尝试并将add分配给挑战和用户,然后将挑战和用户也添加到尝试中。在我看来,这似乎是一个不必要的残酷解决办法

然而,每种方法,例如改变惰性参数、改变查询等,都会导致数百到数千个查询。我还尝试编写简单的SQL查询,以产生我想要的结果,并按照SELECT*FROM challenge中的id和SELECT challenge\u id FROM truments的思路提出了一些想法,效果很好,但我无法将其转换为SQLAlchemy

提前非常感谢您提供的任何指导

实际上,我想从SQLAlchemy中得到的是一次解决所有或所有相关的挑战,然后将其与相关的尝试联系起来。如果所有的挑战都被解决了,或者只是在以后才有实际联系,这并不是什么大不了的事

首先要从关系优先中去掉lazy='subquery'指令;修复关系以始终加载所有内容是查询激增的原因。特别是在这里,你会得到挑战->尝试->挑战的每个lazyload都会加载,所以你在这里设计了最糟糕的加载组合:

解决了这个问题,有两种方法

需要记住的是,在通常情况下,多对一关联首先通过主键从内存中的会话中获取,如果存在,则不会发出SQL。所以我认为你可以得到确切的效果,就像你用我经常使用的技巧描述的那样:

all_challenges = session.query(Challenge).all()

for user in some_users:    # however you got these
    for attempt in user.attempts:   # however you got these
        do_something_with(attempt.challenge)  # no SQL will be emitted
如果您希望将上述方法与Select*from质询(其中id在Select challenge_id from attempt中)一起使用:

all_challenges = session.query(Challenge).\
                  filter(Challenge.id.in_(session.query(UserAttempt.challenge_id))).all()
虽然这可能作为联接更有效:

all_challenges = session.query(Challenge).\
                  join(Challenge.attempts).all()
或者是不同的,我猜该联接将返回与usertrunt中显示的相同的challenge.id:

all_challenges = session.query(Challenge).distinct().\
                  join(Challenge.attempts).all()
attempts = session.query(UserAttempt).\
                  options(joinedload(UserAttempt.challenge)).all()
另一种方法是更具体地使用即时加载。您可以在一个查询中查询一组用户/尝试/挑战,该查询将发出三条SELECT语句:

users = session.query(User).\
              options(subqueryload_all(User.attempts, UserAttempt.challenge)).all()
或者因为usertrument->Challenge是多对一的,所以加入可能更好:

users = session.query(User).\
                  options(subqueryload(User.attempts), joinedload(UserAttempt.challenge)).all()
仅从用户尝试:

all_challenges = session.query(Challenge).distinct().\
                  join(Challenge.attempts).all()
attempts = session.query(UserAttempt).\
                  options(joinedload(UserAttempt.challenge)).all()