SQLAlchemy:通过主键高效/更好的查询?
我正在使用MySQL。
我有一个用户表,采用声明式模式:
class User(Base):
__tablename__ = 'user'
id = Column(u'id', Integer(), primary_key=True)
name = Column(u'name', String(50))
当我有一串用户标识符时,我会用以下方式来获取它们:
user_ids = [1, 2, 3, 4, 5]
users = Session.query(User).filter(User.id.in_(user_ids)).all()
我不喜欢使用 in_
,因为我觉得我学过它在索引字段上的性能不好。这是真的吗?
有没有更好的方法来做这个查询?我该如何用 OR
来写这个查询,使用SQLAlchemy?
3 个回答
@Hadrien(提问者)使用了:
from sqlalchemy.sql.expression import or_
user_ids = [1, 2, 3, 4, 5]
clauses = or_( *[User.user_id==x for x in users] )
users = Session.query(User).filter(clauses).all()
很多性能问题和数据库引擎有关系。接下来这部分内容主要讲的是MySQL。
在使用IN()
这个条件时,如果是在一个有索引的字段上,可能会导致性能不太好,但在你给出的例子中不会有这个问题。对于一定数量的user_ids
,你的查询会是最快的。不过,当user_ids
的数量达到某个点时,把这些ID放到一个临时表里,然后进行join
操作会更快。想了解更多关于IN()
和临时表在MySQL中性能对比的内容,可以查看这篇文章:"MySQL中的参数传递:IN列表与临时表"。
如果这些user_ids
是根据用户的某些特征(比如是管理员或者无效用户)来决定的,你可以在用户表中添加一个字段,这样就可以完全避免这个问题。
使用 in
语句的另一种选择是用 or
来连接多个 ID:
id = 1 or id = 2 or id = 3
如果你只有几个 ID,这样做可能会让速度更快一些。
根据 "常见过滤操作符" 的说明:
from sqlalchemy import or_
filter(or_(User.name == 'ed', User.name == 'wendy'))
你没有说你用的是什么数据库,但你的管理员可能是你最好的帮手。了解使用什么语句的最佳方法是分析查询,并尝试几种不同的方式,这样你就能知道你的数据库引擎对这些方式的处理效果如何。无论你使用什么数据库,只要它支持 or
或 in
,那么使用这些方式通常会比一个个查询所有 ID 更快。
其实,担心用 in
还是其他语句,可能对整个应用的速度影响不大,相比之下,改动代码的其他部分可能会更有效。现在的数据库引擎在优化简单查询方面做得相当不错,只要你的查询合理,就能获得良好的性能。
我们在编程中需要学习的一件事是,先让代码正常工作,然后再测试和优化,如果有问题的话。我们常常以为知道瓶颈在哪里,但使用性能分析工具可能会让我们发现其实并不是这样。使用性能分析器和基准测试工具可以帮助我们找出问题所在,并显示出加速需要调整的最佳方法。