查询数据库时提高页面速度

时间:2013-07-20 18:09:33

标签: mysql flask query-optimization jinja2 flask-sqlalchemy

我正在使用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。该表由以下主题函数first table from this link包装,虽然在某些列上禁用排序功能有帮助,但它仍然非常慢。

所以,我想知道,我如何优化此过程或生成模板以使其更快?我在带有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的Amazon EC2实例上运行此操作。一个“明显”的解决方案,一次分页并返回100个左右的记录将真正起作用,因为列表必须包含所有用户以进行排序(主要是日期),因此该解决方案是最后的选择。

提前致谢!

2 个答案:

答案 0 :(得分:5)

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

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

将为所有用户提供Table按每个用户的电子邮件地址排序的所有条目,然后按Table中的日期列。我们使用outerjoin而不是join来确保我们获得用户,即使他们在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())

答案 1 :(得分: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.
 }