GQL查询优化和表架构

时间:2010-08-03 19:42:07

标签: google-app-engine bigtable

我一直在使用Google App Engine,而且我的一些数据查询运行速度很慢。我已经读过,设计一个App Engine数据存储区与使用SQL数据库是一种不同的心态,我不确定我是这样做的最佳方式。我有两个问题要尝试走上正轨:

具体来说:

我有Foo类型和UserFoo类型。每个UserFoo都是对应Foo的“实例”,并保存特定于该实例的数据。我的Foo类型具有fooCode属性,这是一个唯一标识符,我使用UserFoo属性将每个Foo映射到每个fooCode。然后我使用如下代码对每个Foo进行操作:

foos = Foo.all().filter('bar =', bar)
for foo in foos:
    userFoo = UserFoo.all().filter('userKey =', user).filter('fooCode =', foo.fooCode)

注意:我在引用键上使用fooCode,以便我们可以轻松删除并重新添加新的Foo,而不必重新映射所有相应的UserFoo s

一般情况:

设计GAE数据存储表的典型方法和使用它们的最佳实践是什么?

3 个答案:

答案 0 :(得分:1)

一般情况:

  • 尽可能地反规范化。

  • 通过密钥引用实体 只要有可能;这是最快的 从数据存储区中获取数据的方法。

具体来说,如果您使用ReferenceProperty来建立关系而不是进入过滤器的代码,那么您的性能可能会大幅提升。我猜测,查询UserFoo的Foo比删除和重新映射Foo更常见,是吗?在这种情况下,实用和数据存储方面要做的是使用引用属性。

此外,如果可以将Foo-UserFoo关系非规范化为单个实体,则无需完全删除整个查询系列。

答案 1 :(得分:1)

这是staircase of gets反模式。解决方案是ReferenceProperty pre-fetching

遗憾的是你决定不使用ReferenceProperty。我建议你重新考虑这个选择。

  

注意:我正在使用fooCode   参考键使我们可以轻松   删除并重新添加新的Foo而不是   必须重新映射所有   相应的UserFoos。

请记住,实体键只是其路径的编码表示:实体及其任何祖先的种类和名称或ID。如果您删除然后重新创建Foo,则只有给出不同的名称或ID才会有不同的密钥。如果您有某种方式为旧实体和新实体提供相同的fooCode,您可以轻松地使用fooCode作为密钥名称,这将允许删除然后重新添加{{1保留原始密钥。

答案 2 :(得分:1)

我建议进行以下更改:

  1. 使用UserFoo中的ReferenceProperty来引用其Foo,或者在适当的情况下将其设为子实体。我不理解您关于重新映射现有实体的评论 - 这绝不是必要的。
  2. 将“bar”属性的副本添加到每个UserFoo
  3. 对UserFoo.all()。filter('bar =',bar).order('userKey')执行单个查询。结果将按条形过滤并按用户分组,只需要一个查询,而不是每个用户一个。
  4. 通过在查询上调用.fetch()来获取结果,而不是迭代它们。这样效率更高。
  5. 如果需要,请使用ReferenceProperty prefetching检索每个UserFoo的Foo对象。