2015-11-19 26 views
1

设计更智能的查询方法。专为目前检索目的的查询是:SQLAlchemy中的.join()和.has()/ .any()之间的区别

query_retrieve = self.session.query(Assessment_Result).\ 
      filter(Assessment_Result.owner.has(User.username == owner)).\ 
      filter(Assessment_Result.assessment.has(Assessment.name == assessment)).one() 

这使得使用SQLAlchemy的EXISTS关键字。这在运行nosetests时有效,但稍后会出现问题。我需要设计一个更好的查询方法,使用.join()进行相同类型的比较,并返回.one()。更重要的是,我想更好地理解为什么.join()方法是查询的有效方法。

我花了一些时间试图分解SQLAlchemy文档,并发现以下信息有用,但可以使用更多的帮助来设计使用.join()的查询方法,以及为什么它更好。 [版本:2.7.9的Python和SQLAlchemy的1.0.9]

基础上docs

Query.join()推荐的形式:

如果没有外键或几个查询。 join()方法效果更好 当使用下列形式之一:

query.join(Address, User.id==Address.user_id) # explicit condition 
query.join(User.addresses)      # specify relationship from left to right 
query.join(Address, User.addresses)    # same, with explicit target 
query.join('addresses')       # same, using a string 

个布尔运算符:.has().any()(我的上述代码)

的存在于SQL关键字是一个布尔运算符,如果 给定表达式包含任何行返回true。它可以在许多场景中用于代替连接,也可用于查找在相关表中没有相应行的行 。

表设计:

class Assessment_Result(Base): 
    __tablename__ = 'assessment_results' 

    owner_id = Column(Integer, ForeignKey('users.id')) 
    owner = relationship('User', backref='assessment_result') 

    assessment_id = Column(Integer, ForeignKey('assessments.id')) 
    assessment = relationship('Assessment', backref='assessment_result') 

回答

-1

对于您的查询,或多或少转换为SQL

SELECT * FROM 
Assessment_Result a 
WHERE (EXISTS (SELECT 1 FROM User u 
       WHERE u.id = a.owner_id AND u.username = :owner)) 
AND (EXISTS (SELECT 1 FROM Assessment s 
       WHERE s.id = a.assessment_id AND s.name = :assessment)) 

,因为它包含两个相关子查询,这可能是低效的,特别是对于那些没有按数据库没有子查询优化。对于我们正在扫描的整个Assessment_result表中的每一行,我们必须一次性扫描用户表以存在以及评估表一次。如果让我们说用户相对来说是一个巨大的表,并且没有被索引,那么性能是最差的。从你的问题来看,我不知道你使用了什么数据库,或者表格是如何被索引等以评论性能的。

这可能是更好的加入在这种情况下表,使得SQL成为

SELECT * FROM 
Assessment_Result a, 
User u, 
Assessment s 
WHERE a.owner_id = u.id 
AND u.username = :owner 
AND a.assessment_id = s.id 
AND s.name = :assessment 

随着加入由数据库的优化来确定订单的正确选择,我们允许分贝,以减少结果集早期。 例如,如果连接顺序为user-> assessment_result-> assessment,那么我们首先通过扫描整个用户表一次匹配条件(u.username =:owner),然后返回x个结果来筛选用户。

然后我们扫描评估结果表x次,得到y个合并结果。最后,扫描评估y次以获得最终产品。请注意,y < = x < =用户表的大小。

与第一个查询相比,在最坏的情况下,我们扫描用户和评估的次数与Assessment_result表中的行数相同。

+0

这与SQLAlchemy无关,这是提问者特别要求的内容。 – DNelson