2010-08-03 69 views
0

我一直在使用Google App Engine,并且遇到一些数据查询缓慢的问题。我读过设计一个App Engine数据存储区与使用SQL数据库不同的思维模式,我不确定我是否以最好的方式来做这件事。我有两个问题,试图得到正确的轨道上:GQL查询优化和表架构

具体做法是:

我有一个Foo类型和UserFoo类型。每个UserFoo是对应的Foo的“实例”并保存特定于该实例的数据。我的Foo类型有一个fooCode属性,它是一个唯一的标识符,我使用它们的fooCode属性将每个UserFoo与各个Foo映射。然后,我对每个富的代码运行,像这样:

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

注:我使用fooCode超过参考键,以便我们可以很容易地删除并重新添加新Foo S和不必再重新映射所有对应UserFoo s。

一般来说:

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

+0

Foo和UserFoo对象之间是否存在1对1的对应关系? – 2010-08-03 19:46:27

+0

请注意,您所展示的实际上并不是一个GQL查询。 – 2010-08-03 19:48:50

+0

1 Foo许多用户信息。另外,我最初调用的是GqlQuery,但改变了它们,因为我读得比较慢。 – 2010-08-03 19:52:54

回答

1

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

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

注:我使用fooCode在 参考键,以便我们可以很容易地 删除并重新添加新的Foo而不是 有那么重新映射所有 相应UserFoos。

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

+0

阅读这些链接很有意义。我现在正在修改我的数据存储。感谢所有谁指出了这一点! – 2010-08-04 22:23:02

1

一般来说:

  • 去正规化尽可能。

  • 尽可能通过钥匙 提及实体;它是最快的从数据存储中获取数据的方式。

具体而言,如果您使用ReferenceProperty建立关系而不是进入过滤器的代码,那么您的性能可能会大幅提升。我会猜测,查询UserFoo的Foo比删除和重新映射Foo更经常发生,是的?在这种情况下,务实和数据存储明智的做法是使用引用属性。另外,如果Foo-UserFoo关系可以非规范化为单个实体,则完全不需要整个系列的查询。

1

我建议以下变化:

  1. 使用的ReferenceProperty在UserFoo指其富,或者如果合适的话使子实体。我不明白你对重新映射现有实体的评论 - 这不应该是必要的。
  2. 为每个UserFoo添加一个'bar'属性的副本
  3. 对UserFoo.all()。filter('bar =',bar).order('userKey')执行一次查询。结果将按栏过滤并按用户分组,只需要一个查询,而不是每个用户一个。
  4. 通过在查询上调用.fetch()来获取结果,而不是遍历它们。这样更有效率。
  5. 如果需要,可使用ReferenceProperty prefetching检索每个UserFoo的Foo对象。