我的应用程序中存在延迟问题,因为数据存储区对引用的实体执行了其他查询。关于如何通过使用get_value_for_datastore()函数来处理单值属性,我收到了good advice。但是我的应用程序也有一对多关系,如下面的代码所示,我还没有找到预取这些实体的方法。当试图显示包含200个文档及其相关documentFiles(> 6000ms)的表时,结果是不可接受的延迟。
(可能永远不会有超过10,000个文档或DocumentFiles)
有没有办法解决这个问题?
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)
...
class DocumentFile(db.Model):
description= db.StringProperty()
blob = blobstore.BlobReferenceProperty()
created = db.DateTimeProperty() # needs to be stored here in relation to upload / download of everything
document = db.ReferenceProperty(Document, collection_name = 'files')
@property
def link(self):
return '<a href="/file/serve/%s">%s</a>' % (self.key().id(),self.blob.filename)
...
main.py
docUsers = DocUser.all()
docUsersNameDict = dict([(i.key(), i.name) for i in docUsers])
documents = Document.all()
for d idocuments:
out += '<td>%s</td>' % d.title
docUserKey = Document.lastEditedBy.get_value_for_datastore(d)
out +='<td>%s</td>' % docUsersNameDict.get(docUserKey)
out += '<td>'
# Creates a new query for each document, resulting in unacceptable latency
for file in d.files:
out += file.link + '<br>'
out += '</td>'
答案 0 :(得分:2)
将文档中的链接反规范化并存储,以便快速获取链接。
您需要注意,更新DocumentFile时,需要更新关联的Document。这可以假设您从数据存储区读取链接的频率远远高于更新它的链接。
非规范化通常是App Engine上性能不佳的解决方法。
答案 1 :(得分:1)
异步加载文件。在d.files上使用get_value_for_datastore,它应返回一组键,然后您可以执行db.get_async(key)以返回将来的对象。您将无法像过程那样以程序方式写出结果,但是为所有文档组装部分请求/字典,使用待处理的future future()集合,然后当您进行迭代时,应该是微不足道的。建立结果,你可以最终确定期货,这将完成而不会阻塞{~0ms延迟}。
基本上,您需要两次迭代。第一次迭代将通过并异步请求您需要的文件,第二次迭代将完成,最终确定您的获取并构建您的响应。
https://developers.google.com/appengine/docs/python/datastore/async