如何优化数据存储区中的一对多查询

时间:2012-04-30 13:22:28

标签: google-app-engine google-cloud-datastore python-2.7

我的应用程序中存在延迟问题,因为数据存储区对引用的实体执行了其他查询。关于如何通过使用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>'  

2 个答案:

答案 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