【问题标题】:How to optimize one-to many queries in the datastore如何优化数据存储中的一对多查询
【发布时间】:2012-04-30 13:22:27
【问题描述】:

由于数据存储区对引用的实体进行额外查询,我的应用程序出现延迟问题。我收到了good advice,关于如何使用 get_value_for_datastore() 函数处理单值属性。但是我的应用程序也有一对多的关系,如下面的代码所示,我还没有找到预取这些实体的方法。结果是在尝试显示包含 200 个文档及其相关文档文件的表格时出现不可接受的延迟(>6000 毫秒)。

(可能永远不会超过 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>'  

【问题讨论】:

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


    【解决方案1】:

    对链接进行非规范化并将其存储在您的文档中,以便快速获取链接。

    您需要注意,当您更新 DocumentFile 时,您需要更新关联的 Document。这是在您从数据存储区读取链接的频率远高于更新链接的假设下运行的。

    反规范化通常是解决 App Engine 性能不佳的方法。

    【讨论】:

    • 谢谢。然后对其进行非规范化。无法使用文档中承诺的简洁设计有点令人沮丧,但有时生活就是这样。
    【解决方案2】:

    异步加载文件。在 d.files 上使用 get_value_for_datastore,它应该返回一个键的集合,然后你可以执行 db.get_async(key) 来返回一个未来的对象。您将无法像您所做的那样以程序方式写出您的结果,但是为所有文档组装一个部分请求/字典应该是微不足道的,其中包含待处理的未来 get() 集合,然后当您进行迭代时构建结果,您可以最终确定未来,这将在不阻塞 {~0ms 延迟}的情况下完成。

    基本上,您需要两次迭代。第一次迭代将通过并异步请求您需要的文件,第二次迭代将通过,最终确定您的获取并构建您的响应。

    https://developers.google.com/appengine/docs/python/datastore/async

    【讨论】:

    • 谢谢,但 get_value_for_datastore 只返回一个查询对象 - Document.files.get_value_for_datastore(d) - 所以这不起作用。
    • 如果完整查询对于迭代该查询来说过于昂贵,我是否建议使用投影查询仅返回“链接”属性? developers.google.com/appengine/docs/python/datastore/…query.fetch(projection=('links')) 或 query.run(projection=('links')) 将,提供 links 是一个索引字段,返回一个更快的查询。我仍然认为您应该能够在不运行查询的情况下访问所需文件的密钥;它们必须在您的文档中某处返回...
    猜你喜欢
    • 2012-11-17
    • 1970-01-01
    • 1970-01-01
    • 2017-06-29
    • 2017-09-18
    • 1970-01-01
    • 1970-01-01
    • 2011-08-03
    • 1970-01-01
    相关资源
    最近更新 更多