2012-04-28 5 views
0

아래의 200 개의 Documents and 1 DocUser를 실행하면 스크립트는 AppStats에 따라 약 5000ms가 소요됩니다. 마지막으로 6-51ms 걸리는 lastEditedBy (datastore_v3.Get)의 잠금이 발생할 때마다 데이터 저장소에 요청이 있음을 알 수 있습니다.데이터 저장소에 대한 요청 수를 줄이는 방법

내가 뭘 하려는지는 다른 엔티티에서 파생 된 여러 속성을 가진 많은 엔티티를 표시하는 것을 가능하게 만드는 것입니다. 많은 엔티티 (<000)가있을 수 없으며 관리자 인터페이스 이상의 것이므로 동시 사용자가 절대 없을 것입니다.

DocUser 엔티티를 캐싱하여 최적화하려고 시도했지만 데이터 저장소에 새로운 요청을하지 않고 위 쿼리에서 DocUser 키를 가져올 수 없습니다.

1) 이것이 의미있는가요? 내가 겪고있는 대기 시간이 정상입니까?

2) 데이터 저장소에 대한 추가 요청없이이 작업을 수행 할 수있는 방법이 있습니까?

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

main.py

$out = '<table>' 
documents = Document.all() 
for i,d in enumerate(documents):   
    out += '<tr><td>%s</td><td>%s</td></tr>' % (d.title, d.lastEditedBy.name) 
$out = '</table>' 
+0

왜 문서에서 루핑을하고 루프에서 매번 그 모든 내용을 가져 오는 중입니까? main.py에 문제가 있습니다. – mjibson

+0

죄송합니다, 예제 코드에서 오류가 발생했습니다. 이제 해결되었습니다. –

답변

1

키를 docuser.key()로, 값을 docuser.name으로 사용하여 모든 사전 작성자를 사전 검색하여 조회 사전을 작성하십시오.

docusers = Docuser.all().fetch(1000) 
    docuser_dict = dict([(i.key(), i.name) for i in docusers]) 

그런 다음 코드에서, 당신은 데이터 저장소에서 개체를 끌어없이()을 docuser.key를 얻을 수 get_value_for_datastore를 사용하여 docuser_dict에서 이름을 얻을 수 있습니다.

documents = Document.all().fetch(1000) 
    for i,d in enumerate(documents): 
     docuser_key = Document.lastEditedBy.get_value_for_datastore(d) 
     last_editedby_name = docuser_dict.get(docuser_key) 
     out += '<tr><td>%s</td><td>%s</td></tr>' % (d.title, last_editedby_name) 
+0

고맙습니다. 위대한 작품입니다. –

4

이것은 일반적인 안티 패턴이다. 이 문제를 해결하려면 다음을 수행하십시오.

+0

의견을 보내 주셔서 감사합니다. 나는 이제 GAE 데이터 저장소가 내가 생각했던 것처럼 진보되고 쉬운 일이 아니라는 것을 이해한다. 아마 대신 NBC를 사용해야하지만 전체 응용 프로그램을 다시 작성해야 할 필요가 있습니다. Nick 코드가 작동하지 않을 수 있으며 블로그에 뭔가 더 이상 작동하지 않는다는 의견이 몇 가지 있습니다. 최근에 이것을 테스트 해 보셨습니까? –

1

는 인스턴스 시간을 절감하려는 경우, 당신은 당신이 다른 일을하면서 결과를 프리 페치 할 수있는 여러 비동기 쿼리에 하나의 동기 쿼리를 중단 할 수 있습니다. Document.all(). fetch()를 사용하는 대신 Document.all(). run()을 사용하십시오. 반복하는 첫 번째 쿼리를 차단해야 할 수 있지만 완료 될 때까지 다른 모든 쿼리의 결과로드가 완료됩니다. 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) 

나는 내 crummy python을 사과합니다. 그러나 아이디어는 간단합니다. prefetch_size = batch_size = limit를 설정하고 모든 쿼리를 한 번에 시작하십시오. q1은 먼저 블록을 차단하기 때문에 크기가 작으므로 블로킹은 시간 낭비입니다. q1이 완료 될 때까지는 q2가 완료되거나 거의 완료되며, q3-5에서는 지연 시간이 0이됩니다.

자세한 내용은 https://developers.google.com/appengine/docs/python/datastore/async#Async_Queries을 참조하십시오.

+0

감사합니다. 이것은 흥미 롭습니다. 그러나 제 응용 프로그램을 합리적으로 수행하기 위해 이러한 종류의 해킹을 수행 할 필요가 없기를 바랍니다. –

+0

이것은 실제로 해킹이 아닙니다. 이것이 앱 엔진의 힘을 여는 방법입니다. 그것은 평행하게 5 ~ 10 개의 쿼리를 편안하게 처리 할 수 ​​있으며 이것을 단일 메소드 def 다중 쿼리 (...)로 마무리 할 수 ​​있습니다. 나는 appengine java에서 항상이 작업을 수행하고 $ 70/day에서 $ 25/day로 비용을 절감했습니다. 비동기 모든 것을 사용하십시오. 모든 appengine 서비스는 비동기로 사용할 수 있습니다. 이는 인스턴스 시간을 최소한으로 줄이는 방법입니다. – Ajax

+0

또한 DocUser 참조 속성으로 인해 동일한 엔티티에서 비싼 반복 gets()가 발생하는 경우 iterating하는 동안 각 조회 속성의 키를 캐싱 한 다음 고유 키만 확인하여 한 번만 가져 오는 것이 좋습니다. 일단. 비동기 적으로이 작업을 수행하는 것이 좋습니다. 가능하다면. – Ajax

관련 문제