2012-04-30 101 views
0

由於數據存儲區對引用的實體執行附加查詢,因此我的應用程序中存在延遲問題。我通過使用get_value_for_datastore()函數收到了關於如何處理單值屬性的good advice。然而,我的應用程序也有一對多的關係,如下面的代碼所示,我還沒有找到預取這些實體的方法。嘗試顯示200個文檔及其相關文檔文件(> 6000毫秒)的表時,結果是不可接受的延遲。如何優化數據存儲區中的一對多查詢

(有可能永遠不會超過10000個文檔或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

非規範化和鏈接存儲在文檔中,以便獲取鏈接將會很快。

當您更新DocumentFile時,您需要小心,您需要更新關聯的文檔。假設您從數據存儲中讀取鏈接的次數比您更新的時間更長。

非規範化通常是解決App Engine性能不佳的問題。

+0

謝謝。非正規化它是。這是一種士氣低落,不能使用文檔中承諾的乾淨設計,但這就是生活有時是如此。 –

1

異步加載文件。在d.files上使用get_value_for_datastore,它應該返回一組鍵,然後您可以執行db.get_async(key)來返回未來的對象。你不能像你所做的那樣程序化地寫出你的結果,但是爲所有文檔組裝一個部分請求/字典並且收集待處理的將來獲取(),應該是微不足道的,然後當你重複建立結果,您可以完成未來的完成,而不會阻塞{〜0ms延遲}。

基本上,你需要兩次迭代。第一次迭代將通過並異步請求所需的文件,第二次迭代將完成,最終確定獲取並構建響應。

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

+0

謝謝,但get_value_for_datastore只是返回一個Query對象 - Document.files.get_value_for_datastore(d) - 因此不起作用。 –

+0

如果完整查詢對迭代查詢來說太昂貴,我可以建議使用投影查詢來返回「鏈接」屬性嗎? https://developers.google.com/appengine/docs/python/datastore/queries#Query_Projection query.fetch(projection =('links'))or query.run(projection =('links'))將提供的鏈接是一個索引字段,返回一個更快的查詢。我仍然認爲你應該能夠在不運行查詢的情況下訪問你想要的文件的密鑰;他們必須在您的文檔中返回... – Ajax