我们在 Python 2.7.7 和 Postgres 9.3 上使用 SQLAlchemy 0.9.8。
我们有一个查询,它使用 joinedloads 使用单个查询完全填充一些 Recipe 对象。该查询创建了一个大型 SQL 语句,需要 20 秒才能执行 - 太长了。这是 rendered SQL statement on Pastebin .
呈现的 SQL 有一个 ORDER BY 子句,Postgres 解释说这是 99% 的时间花在这个查询上的来源。这似乎来自 ORM 模型中的关系,它有一个 order_by 子句。
但是,我们不关心此查询返回结果的顺序 - 我们只关心查看单个对象时的顺序。如果我在呈现的 SQL 语句末尾删除 ORDER BY 子句,查询将在不到一秒的时间内执行 - 完美。
我们尝试在查询中使用 .order_by(None),但这似乎没有效果。 ORDER BY 似乎与 joinedloads 有关,因为如果将 joinedloads 更改为 lazyloads,它们就会消失。但是我们需要联合负载来提高速度。
如何让 SQLAlchemy 省略 ORDER BY 子句?
仅供引用,这是查询:
missing_recipes = cls.query(session).filter(Recipe.id.in_(missing_recipe_ids)) if missing_recipe_ids else []
这是 ORM 类的摘录:
class Recipe(Base, TransactionalIdMixin, TableCacheMixin, TableCreatedModifiedMixin):
__tablename__ = 'recipes'
authors = relationship('RecipeAuthor', cascade=OrmCommonClass.OwnedChildCascadeOptions,
single_parent=True,
lazy='joined', order_by='RecipeAuthor.order', backref='recipe')
scanned_photos = relationship(ScannedPhoto, backref='recipe', order_by="ScannedPhoto.position")
utensils = relationship(CookingUtensil, secondary=lambda: recipe_cooking_utensils_table)
utensil_labels = association_proxy('utensils', 'name')
我们的 query() 方法看起来像这样(省略了更多的 joinedloads):
@classmethod
def query(cls, session):
query = query.options(
joinedload(cls.ingredients).joinedload(RecipeIngredient.ingredient),
joinedload(cls.instructions),
joinedload(cls.scanned_photos),
joinedload(cls.tags),
joinedload(cls.authors),
)
最佳答案
[从我在邮件列表上的回答中复制]
您要么需要从 relationship() 中删除 order_by,如果排序不重要,这可能是最好的主意,或者跳过 joinedload(),自己写出连接并使用 contains_eager()(http://docs.sqlalchemy.org/en/rel_0_9/orm/loading_relationships.html?highlight=contains_eager#contains-eager)。
joinedload() 是一种宏,它创建连接和对查询的其他修改(例如 ORDER BY 关系),对每个部分应用别名,这样它们就不会与查询中的任何内容发生冲突,然后将这些额外的 FROM 子句中的列路由到集合和相关对象中。 contains_eager() 只做最后一部分。在这种情况下,前两部分,即编写连接和排序以及可能为它们添加别名(或不添加别名)由您决定,因此您可以完全控制查询的呈现方式。
关于python - SQLAlchemy:joinedload 子条款查询的 order_by(无)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27712919/