Google app engine 哪种NDB查询函数在遍历一大组查询结果时更有效?

Google app engine 哪种NDB查询函数在遍历一大组查询结果时更有效?,google-app-engine,Google App Engine,我在我的应用程序中使用NDB,并使用iter()和limit和start cursor在一个任务中迭代20000个查询结果。很多时候我都会遇到超时错误 超时:数据存储操作超时,或数据暂时不可用 我打电话的方式是这样的: results = query.iter(limit=20000, start_cursor=cursor, produce_cursors=True) for item in results: process(item) save_cursor_for_next_time(

我在我的应用程序中使用NDB,并使用iter()和limit和start cursor在一个任务中迭代20000个查询结果。很多时候我都会遇到超时错误

超时:数据存储操作超时,或数据暂时不可用

我打电话的方式是这样的:

results = query.iter(limit=20000, start_cursor=cursor, produce_cursors=True)
for item in results:
  process(item)
save_cursor_for_next_time(results.cursor_after().urlsafe())
我可以降低限制,但我认为一项任务可以运行长达10分钟。10分钟的时间应该足以完成20000个结果。事实上,如果运行良好,任务可以在大约一分钟内完成

如果我切换到fetch()或fetch_page(),它们会更高效,并且不太可能出现超时错误吗?我怀疑iter()中有很多开销导致超时错误


谢谢。

ndb还需要考虑其他方面,比如上下文缓存,您需要禁用它。但我也用了国际热核聚变实验堆的方法。我还使用旧的db制作了映射器api的ndb版本

以下是我的ndb映射器api,它可以解决超时问题和ndb缓存,并轻松创建此类内容:

有了这个MapperAPI,您可以像创建它一样创建它,也可以改进它

class NameYourJob(Mapper):

    def init(self):
        self.KIND = YourItemModel
        self.FILTERS = [YourItemModel.send_email == True]

    def map(self, item):
        # here is your process(item)
        # process here
        item.send_email = False
        self.update(item)

# Then run it like this
from google.appengine.ext import deferred
deferred.defer(NameYourJob().run, 50,  # <-- this is your batch 
    _target='backend_name_if_you_want', _name='a_name_to_avoid_dups')
类名yourjob(映射器):
def初始化(自):
self.KIND=YourItemModel
self.FILTERS=[YourItemModel.send_email==True]
def映射(自身,项目):
#这是您的流程(项目)
#在这里处理
item.send_email=False
自我更新(项目)
#然后像这样运行它
从google.appengine.ext导入延迟

deferred.deferred(NameYourJob().run,50,#Fetch实际上并没有更高的效率。它们都使用相同的机制,除非您知道需要预先获取多少个实体,否则Fetch可以更高效,因为您只需要一次往返

您可以增加iter的批处理大小,这可以改善情况。请参阅

根据文档,默认批量大小为20,这意味着对于20000个实体而言,需要大量批量

其他可以帮助的事情。考虑使用MAP和MAPYASYNC处理,而不是显式调用进程(实体)有一个读,也将AsYNC引入到处理中意味着改进的并发性。


说到这里,您应该对时间进行分析,以便了解时间在哪里使用。例如,由于您在
过程中所做的事情,延迟可能会出现在
过程中。

对于可能很长的查询迭代,我们使用时间检查来确保可以处理缓慢的处理。考虑到GAE基础结构性能的差异nce,您可能永远也找不到最佳的处理编号。下面的代码摘录来自我们使用的在线维护处理程序,该处理程序通常在10秒钟内运行。如果没有,我们会收到一个返回代码,表示由于我们的计时器检查,它需要再次运行。在您的情况下,您可能会在将光标传递到下一个qu后中断该进程eue任务。下面是一些经过编辑的示例代码,希望能让您对我们的逻辑有一个很好的了解。另一个注意事项:您可以选择将其分解为较小的部分,然后将任务重新排队,直到任务完成。在GAE高度多变的环境中,一次完成20k项任务似乎非常有挑战性。HTH-stevp

def over_dt_limit(start, milliseconds):
    dt = datetime.datetime.now() - start
    mt = float(dt.seconds * 1000) + (float(dt.microseconds)/float(1000))
    if mt > float(milliseconds):
        return True
    return False


    #set a start time
    start = datetime.datetime.now()
    # handle a timeout issue inside your query iteration
    for item in query.iter():
        # do your loop logic
        if over_dt_limit(start, 9000):
            # your specific time-out logic here
            break

我不太明白为什么需要在mapper中禁用上下文缓存?这真的有什么帮助?已经有一段时间了,但如果我没记错的话,我这么做是为了在更新实体时不会创建上下文缓存,这会在它运行的实例上产生不必要的开销。