0

以下を200個のドキュメントと1個のDocUserで実行すると、AppStatsによるとスクリプトに約5000ミリ秒かかります。問題は、lastEditedBy(datastore_v3.Get)のロックアップごとにデータストアにリクエストがあり、それぞれ6〜51ミリ秒かかることです。

私がやろうとしているのは、いくつかのプロパティが他のエンティティから派生している多くのエンティティを表示できるようにすることです。エンティティの数が多くなることはなく(<5000)、これは管理インターフェイスであるため、同時に多くのユーザーが存在することはありません。

DocUserエンティティをキャッシュして最適化しようとしましたが、データストアに新しいリクエストを行わないと、上記のクエリからDocUserキーを取得できません。

1)これは理にかなっています-私が経験しているレイテンシーは正常ですか?

2)データストアへの追加リクエストなしでこれを機能させる方法はありますか?

models.py

class Document(db.Expando):
    title = db.StringProperty()
    lastEditedBy = db.ReferenceProperty(DocUser, collection_name = 'documentLastEditedBy')  
...

class DocUser(db.Model):
    user = db.UserProperty()
    name = db.StringProperty()  
    hasWriteAccess= db.BooleanProperty(default = False)
    isAdmin = db.BooleanProperty(default = False)
    accessGroups = db.ListProperty(db.Key)
...

main.py

$out = '<table>'   
documents = Document.all()
for i,d in enumerate(documents):        
    out += '<tr><td>%s</td><td>%s</td></tr>' % (d.title, d.lastEditedBy.name)
$out = '</table>'
4

3 に答える 3

4

これは典型的なアンチパターンです。これを回避するには、次の方法があります。

于 2012-04-28T23:27:54.827 に答える
1

これを行う1つの方法は、すべてのドキュサーをプリフェッチしてルックアップディクショナリを作成することです。キーはdocuser.key()で、値はdocuser.nameです。

    docusers = Docuser.all().fetch(1000)
    docuser_dict = dict( [(i.key(), i.name) for i in docusers] )

次に、コードで、get_value_for_datastoreを使用してデータストアからオブジェクトをプルせずにdocuser.key()を取得することにより、docuser_dictから名前を取得できます。

    documents = Document.all().fetch(1000)
    for i,d in enumerate(documents):
        docuser_key = Document.lastEditedBy.get_value_for_datastore(d)
        last_editedby_name = docuser_dict.get(docuser_key)
        out += '<tr><td>%s</td><td>%s</td></tr>' % (d.title, last_editedby_name)
于 2012-04-29T04:40:43.260 に答える
1

インスタンス時間を短縮したい場合は、単一の同期クエリを複数の非同期クエリに分割できます。これにより、他の作業を行っているときに結果をプリフェッチできます。Document.all()。fetch()を使用する代わりに、Document.all()。run()を使用します。繰り返す最初のクエリをブロックする必要があるかもしれませんが、それが完了するまでに、他のすべてのクエリは結果の読み込みを終了します。200のエンティティを取得する場合は、一度に5つのクエリを使用してみてください。

q1 = Document.all().run(prefetch_size=20, batch_size=20, limit=20, offset=0)
q2 = Document.all().run(prefetch_size=45, batch_size=45, limit=45, offset=20)
q3 = Document.all().run(prefetch_size=45, batch_size=45, limit=45, offset=65)
q4 = Document.all().run(prefetch_size=45, batch_size=45, limit=45, offset=110)
q5 = Document.all().run(prefetch_size=45, batch_size=45, limit=45, offset=155)
for i,d in enumerate(q1):        
    out += '<tr><td>%s</td><td>%s</td></tr>' % (d.title, d.lastEditedBy.name)
for i,d in enumerate(q2):        
    out += '<tr><td>%s</td><td>%s</td></tr>' % (d.title, d.lastEditedBy.name)
for i,d in enumerate(q3):        
    out += '<tr><td>%s</td><td>%s</td></tr>' % (d.title, d.lastEditedBy.name)
for i,d in enumerate(q4):        
    out += '<tr><td>%s</td><td>%s</td></tr>' % (d.title, d.lastEditedBy.name)
for i,d in enumerate(q5):        
    out += '<tr><td>%s</td><td>%s</td></tr>' % (d.title, d.lastEditedBy.name)

不器用なPythonについてお詫びします。しかし、アイデアは単純です。prefetch_size = batch_size = limitを設定し、すべてのクエリを一度に開始します。q1は最初にブロックするため、サイズが小さくなります。ブロックすると時間が無駄になります。q1が完了するまでに、q2は完了するか、ほぼ完了します。q3-5では、待ち時間はゼロになります。

詳細については、 https://developers.google.com/appengine/docs/python/datastore/async#Async_Queriesをご覧ください。

于 2012-04-29T20:07:54.173 に答える