6

我有一个包含大约 150,000 个实体的数据存储。当我使用过滤器查询商店时,我的查询真的很慢。我的结构是完全平坦的,即每个实体都是彼此的兄弟。

1:使用GQL代替过滤器会更好吗?

2:这不是数据存储的最佳用例吗,我应该改用 SQL 数据库吗?

这是我的代码示例:

// Look for a buy opportunity
dateFilter = new FilterPredicate("date", FilterOperator.EQUAL, dt);
scoreFilter = new FilterPredicate("score", FilterOperator.LESS_THAN_OR_EQUAL, 10.0);
safetyFilter = new FilterPredicate("score", FilterOperator.GREATER_THAN_OR_EQUAL, -1.0);
mainFilter = CompositeFilterOperator.and(dateFilter,scoreFilter,safetyFilter);
q = new Query("StockEntity",stockKey).setFilter(mainFilter);
q.addSort("score", Query.SortDirection.ASCENDING);

stocks = datastore.prepare(q).asList(FetchOptions.Builder.withLimit(availableSlots));

更多细节:

  1. 150,000 条记录,分为 500 只股票,因此每只股票大约 300 条记录,一个日期范围内的每一天。

  2. 像上面这样的查询,其中传递了一个特定的日期,并根据“分数”有效地过滤了 500 只股票,希望返回的记录数在 10 到 20 之间需要 30 秒以上才能完成,在我的开发机器。

还没有尝试过投入生产,但我想接下来我会尝试——我认为不会有太大的不同。我的开发机器是相当高规格的 iMac。

4

2 回答 2

0

https://developers.google.com/appengine/docs/java/datastore/queries#Java_Restrictions_on_queries

不等式过滤器仅限于最多一个属性

为了避免扫描整个索引表,查询机制依赖于所有查询的潜在结果在索引中彼此相邻。为满足此约束,单个查询不得在其所有过滤器中对多个属性使用不等式比较(LESS_THAN、LESS_THAN_OR_EQUAL、GREATER_THAN、GREATER_THAN_OR_EQUAL、NOT_EQUAL)。例如,以下查询是有效的,因为两个不等式过滤器都适用于同一个属性:

简短的回答是,你真的不能用数据存储做你想做的事。

于 2013-08-20T21:45:06.540 回答
0

首先,该查询将在实际数据存储上运行得更快。

  1. 使用 GQL 或 Filters 基本相同。

  2. 使用数据存储时,您应该首先定义您需要的功能。例如:您想要显示具有特定订单和过滤器的股票列表。现在查看您的应用所需的相同数据的任何其他视图。然后决定如何构建数据。

这与 RDBMS 非常不同,在 RDBMS 中,数据库通常可以在不更改数据模型的情况下容纳大多数功能,并且数据以更“通用”的方式(规范化)建模。

通常,如果您知道要读取的任何内容的 KEY,则 Datastore 的读取性能将是最佳的,并且在执行查询时它将执行最差,因为这总是需要索引“扫描”。

知道这一点,我倾向于经常使用祖先关系。请求祖先的“孩子”似乎表现更好并且是一致的。例如,我使用如下查询:

SELECT * WHERE ANCESTOR IS {key}

其中 {key} 是祖先(或“父”)的键。此查询返回祖先实体和在其路径中具有此祖先键的所有实体。在极少数情况下,我使用其中一个过滤器作为父“值”来对对象进行分组,但要小心,一旦写入实体,键就不可更改(您可以更改键,但会产生副本)。

另外,如果您知道“集合”的平均大小。例如,属于 Order 的 Orderlines。您可以选择在某处跟踪每个 Orderline 键。请求批量读取中的前 20 个键是一项快速操作。这与索引基本相同,但是排序和过滤可以在“写入时”完成,因此您的列表仅包含与您的过滤器匹配的键。

避免创建允许用户“动态”选择过滤器的视图。

如何进一步优化: 1. 使用非规范化来最小化查找或查询的数量。2. 尽可能缓存(Memcache)。

于 2015-05-23T10:01:29.857 回答