首页 > 解决方案 > 使用in_()方法后sqlalchemy查询很慢

问题描述

filters.append(Flow.time_point >= datetime.strptime(start_time, '%Y-%m-%d %H:%M:%S'))
filters.append(Flow.time_point <= datetime.strptime(end_time, '%Y-%m-%d %H:%M:%S'))
if domain_name != 'all':
    filters.append(Bandwidth.domain_name.in_(domain_name.split('|')))

flow_list = db.session.query(Flow.time_point, db.func.sum(Flow.value).label('value')).filter(*filters).group_by(Flow.time_point).order_by(Flow.time_point.asc()).all()

当 domain_name 为 时查询时间为 3 到 4 秒'all',否则查询时间为 5 分钟。我试图向列添加索引,但无济于事。这可能是什么原因?

标签: pythonsqlalchemy

解决方案


什么时候domain_name不是'all'你最终在andCROSS JOIN之间执行隐式。当您将谓词添加到过滤器列表时,SQLAlchemy 也会将其作为对象。由于两者之间没有显式连接,因此查询最终将类似于:FlowBandwidthINBandwidthFROM

SELECT flow.time_point, SUM(flow.value) AS value FROM flow, bandwidth WHERE ...
                                                         -- ^
                                                         -- `- This is the problem

在最坏的情况下,规划器会生成一个查询,该查询首先将来自 的每一行与来自Flow的每一行连接起来Bandwidth。如果您的表甚至中等大,那么生成的行集可能会很大。

如果没有看到您的模型,就不可能产生精确的解决方案,但一般来说,您应该在查询中包含正确的连接,如果您包括Bandwidth

query = db.session.query(Flow.time_point, db.func.sum(Flow.value).label('value'))

filters.append(Flow.time_point >= datetime.strptime(start_time, '%Y-%m-%d %H:%M:%S'))
filters.append(Flow.time_point <= datetime.strptime(end_time, '%Y-%m-%d %H:%M:%S'))

if domain_name != 'all':
    query = query.join(Bandwidth)
    filters.append(Bandwidth.domain_name.in_(domain_name.split('|')))

flow_list = query.\
    filter(*filters).\
    group_by(Flow.time_point).\
    order_by(Flow.time_point.asc()).\
    all()

如果没有连接您的模型的外键,则必须将该ON子句作为第二个参数Query.join()显式提供。


推荐阅读