1

我正在为我正在开发的一个应用程序使用 Flask,以及用于存储数据的 sqlalchemy 和 MySQL 数据库。Jinja2 用于模板。在开发过程中,一切都很好,但现在当使用更大的数据集时,一些包含大量数据的网页的渲染速度非常慢。例如,用户列表由以下代码处理:

def users():
    q = Users.query.all()
    out = []
    for i in q: 
        try:
            something_i_need = Table.query.filter_by(email=i.email).order_by(Table.date).first().id
        except:
            something_i_need = 0
        out.append({
                'id': i.id,
                'last_name': i.last_name,
                'first_name': i.first_name,
                'middle_name': i.middle_name,
                'phone': i.phone,
                'team': i.team,
                'status': i.status,
                'needed': something_i_need,
                'some_more_data': i.some_more_data
            })
    return render_template('users.html', list_of_users=out)

数据有点简化,因为列表中有更多字段。对这个位置的调用,一次查询大约 2000 个用户需要 10 多秒,然后页面的加载也需要 10-20 秒。该表由以下主题函数包装,来自此链接的第一个表,虽然禁用某些列上的排序功能有所帮助,但它仍然非常慢。

所以,我想知道,我怎样才能优化这个过程或模板的生成以使其更快?我在 Amazon EC2 实例上运行它,使用Python 2.7.3 and mod_wsgi, Flask 0.9, Flask-SQLAlchemy=0.16, Jinja2==2.7, MySQL-python=1.2.4, SQLAlchemy=0.8.1. 一个“明显”的解决方案,进行分页并一次返回 100 条左右的记录确实有效,因为列表必须包含所有用于排序目的的用户(主要是日期),因此该解决方案将是最后的手段。

提前致谢!

4

2 回答 2

5

您的问题是您正在运行 N+1 查询(表N中的用户总数在User哪里),其中 1 会做得更好:

User.query \
        .outerjoin(Table, User.email == Table.email) \
        .order_by(User.email, Table.date)

将为您提供所有用户及其所有条目,Table按每个用户的电子邮件地址排序,然后按Table. 我们使用 anouterjoin而不是 ajoin来确保我们获得所有用户,即使他们没有Table.

现在,这并不是我们所需要的——如果存在的话,我们真的很想获得最新的条目。Table可能有更好的方法来做到这一点,但这里有一个带有子查询的简单示例:

last_entry = Table.query \
                  .group_by(Table.email) \
                  .order_by(Table.date) \
                  .subquery()

# Assuming that db is your Flask-SQLAlchemy extension
results = db.session.query(User, last_entry.c.id)  \
    .outerjoin(last_entry, User.email == last_entry.c.email)

然后你可以通过调用来实现查询,然后你就可以all参加比赛了:

return render_template('users.html', list_of_users=results.all())
于 2013-07-20T19:04:28.933 回答
0

首先进行异步查询。其次,维护一个条件流,您应该在其中以块的形式显示返回的结果。例如:

//get lenght of returning cursor
if(//length of returning cursor is greator thatn 10 or something..)
 {
  //Run a loop here and update your UI on UI thread for every 10 values.
 }
于 2013-07-20T18:19:32.083 回答