1

私が取り組んでいる 1 つのアプリケーションに Flask を使用し、データを保存するために sqlalchemy と MySQL データベースを使用しています。テンプレート化には Jinja2 を使用します。開発中はすべて問題ありませんでしたが、より大きなデータセットを使用すると、大量のデータを含む一部の Web ページのレンダリングが非常に遅くなります。たとえば、ユーザーのリストは次のコードで処理されます。

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 程度のレコードを返す 1 つの「明白な」解決策は、並べ替えの目的 (主に日付) のためにすべてのユーザーをリストに含める必要があるため、実際に機能します。そのため、その解決策は最後の手段になります。

前もって感謝します!

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。にエントリがない場合でも、確実にユーザーを取得できるようにouterjoin、 a ではなくan を使用します。joinTable

さて、これは必要なものではありません。最新のエントリが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 に答える