如何减少对数据的请求数

2024-09-30 10:26:47 发布

您现在位置:Python中文网/ 问答频道 /正文

当使用200个文档和1个DocUser运行下面的脚本时,根据AppStats,脚本需要大约5000ms。罪魁祸首是每次锁定lastedby(datastore_v3.Get)时都会向数据存储区发出请求,每次锁定需要6-51毫秒。在

我要做的是使一些东西能够显示许多实体,它们有几个属性,其中一些属性是从其他实体派生出来的。永远不会有大量的实体(<;5000),而且由于这更多是一个管理界面,因此也不会有很多同时使用的用户。在

我试图通过缓存DocUser实体进行优化,但是如果不向数据存储区发出新的请求,就无法从上面的查询中获取DocUser密钥。在

1)这有意义吗-我经历的延迟是否正常?在

2)是否有一种方法可以在不向数据存储区发出额外请求的情况下使其正常工作?在

模型.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)
...

主.py

^{pr2}$

Tags: 数据name文档py实体脚本falsedefault
3条回答

这是典型的反模式。您可以通过以下方法解决此问题:

一种方法是预取所有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_dict获取名称文档用户.key()而不从数据存储中提取对象。在

^{pr2}$

如果您想缩短实例时间,可以将单个同步查询分解为多个异步查询,这样可以在执行其他工作时预取结果。而不是使用文档.all().fetch(),使用文档.all()。运行()。您可能必须阻止您迭代的第一个查询,但当它完成时,所有其他查询都将完成加载结果。如果你想得到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道歉,但想法很简单。设置预取_size=batch_size=limit,一次启动所有查询。q1的尺寸比较小,因为我们会先阻塞它,而阻塞是浪费时间的。到q1完成时,q2将完成或接近完成,q3-5您将支付零延迟。在

有关详细信息,请参见https://developers.google.com/appengine/docs/python/datastore/async#Async_Queries。在

相关问题 更多 >

    热门问题