【问题标题】:How to increase the performance of gae query?如何提高 gae 查询的性能?
【发布时间】:2016-09-09 07:16:30
【问题描述】:

我已经实现了查询表的逻辑,对于该特定表中的每个实体,我必须查找另一个表。

例如

我的代码看起来像,

query = ndb.gql("select * from Foo where user = :1", user.key)
stories, next_cursor, more = query.fetch_page(size, start_cursor=cursor)
if next_cursor:
   for story in stories:
       print story.key
       images = ndb.gql("select * from Images where story = :1", story.key)
       for image in images:
           print image.key
else:
   #do some operations

你看,如果我们将大小设为 10 给 fetch_page 函数,它会分别找到 10 个实体。对于每个实体,我们必须查找另一种Image

这种类型的数据存储查找需要 850 到 950 毫秒。我想减少这个 API 的响应时间。 请注意,我必须从 Story kind 和 Images kind 获取一些列值。

有没有办法通过使用get_multi 方法来缩短查询。或者,我有一个使用memcache 的想法,或者我们应该在Foo 模型中定义一个新的StructuredProperty,它的值必须是Images 模型实体的列表。

我不知道在这种情况下哪个适合..请指导我。

【问题讨论】:

    标签: python performance google-app-engine google-cloud-datastore app-engine-ndb


    【解决方案1】:

    您可以为每个故事添加一个包含图像 ID 列表的属性。我认为这个列表很少改变。然后,您可以轻松get_multi 与故事相关的所有图像,而无需任何查询。

    您还可以考虑在一次调用中将查询返回的所有故事的所有图像get_multi 全部图像,然后在必要时将它们“附加”到代码中的相应故事。

    【讨论】:

    • 你的意思是定义像images = ndb.KeyProperty(kind=Image, repeated=True) 内幕模型?
    • 是的。如果您愿意,可以使用密钥。我经常使用 ids 而不是完整的密钥,因为它们占用的空间更少,而且您总是可以从 id 创建完整的密钥。但是,如果您的数据集不是很大,这可能是不必要的过度优化。而且我是Java这边来的,所以不知道是不是已经在Python中优化过了。
    • 赞这个ndb.key('class_name', id).get()通过id或cls.get_by_id(id)获取实体
    • 是的,但您应该尽可能选择get_multi。这有很大的不同。
    • 如何创建id?我知道id,我们在创建实体时传递的是一个字符串。如何生成唯一 ID?
    【解决方案2】:

    我不知道您项目的整个结构,但是...

    你可以这样做:

    class Story(ndb.Model):
        images = ndb.KeyProperty(kind=Image, repeated=True)
        user = ndb.KeyProperty(kind=User)
    

    并且每次用户添加新图像时都会更新它(Storyimages 属性)。

    然后你就可以使用了:

    images = []
    stories = Story.query.filter(Story.user == user.key)
    stories = stories.fetch(size)
    for story in stories:
        images.extend(ndb.get_multi(story.images))
    print images
    

    希望对您有所帮助。

    【讨论】:

    • 为什么要使用单独的索引模型。我们为什么不在Story 类中定义images = ndb.KeyProperty(kind=Image, repeated=True)
    • 感谢您的回答。
    • 当然可以。我只是不知道所有依赖项。
    • 我有一个疑问.. 如何使用实体 ID 构建密钥? Key('User', 'root', 'User', 5629499534213120, 'LifeStory', 6333186975989760, 'LifestoryImagesMapping', 4925812092436480) 我希望返回具有上述键的实体。但我可以创建一个部分密钥Key('LifestoryImagesMapping', '4925812092436480')
    • 在部分密钥上应用 get() 时,我得到 None 。我知道LifestoryImagesMapping 实体是使用Lifestory 模型的实体键作为父级创建的。
    【解决方案3】:

    你会想看看 NDB 批处理异步 API

       @ndb.tasklet
       def get_stories(user_key):
         stories = yield Story.query(Story.user_key == user_key).fetch_async()
         futs = [
           item.key.get_async() for item in stories]
         result = yield futs
         raise ndb.Return(result)
    
       get_stories(user_key).get_result()
    

    此 API 只会调用 2 个查询。

    1. 查询 DataStore
    2. 上面查询的 N 个结果,进行 1 次查询以获取所有故事

    由于Key.get_async()也自动使用memcache,从你调用上述函数的秒数开始,第二次查询就会调用memcache

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-17
      • 1970-01-01
      • 2013-03-21
      • 1970-01-01
      • 2017-01-21
      • 2013-12-15
      • 1970-01-01
      • 2023-03-24
      相关资源
      最近更新 更多