2010-04-17 68 views
2

我有包括谷歌应用程序引擎:性能与JDO +数据存储可怜

用户提供简单的数据模型:存储基本信息(键,姓名,电话号码等)

关系:形容,例如两个用户(供应relationship_type +两个用户键)

评论之间的友谊:用户发布的(键,注释文本,USER_ID)

我越来越表现很差,举例来说,如果我尝试打印所有用户的朋友的名字。假设用户有500个朋友:我可以很容易地在一个查询中获取好友user_id的列表。但是,为了拔出名字,我必须前往数据存储区执行500次往返访问,每个访问时间似乎约为30毫秒。如果这是SQL,我只需要加入并快速获得答案。

据我所知,在JDO的轻松实现中(如http://gae-java-persistence.blogspot.com所述)在非关系中执行双向连接的基本设施,但它们听起来是实验性的和非标准的(例如,我的代码无法工作任何其他的JDO实现)。

更糟糕的是,如果我想抽出用户朋友发布的所有评论,该怎么办。然后,我需要从用户 - >关系 - >评论,即三向连接,甚至没有实验性支持。来回500次来获得朋友列表的额外开销+另外500次来查看是否有来自用户朋友的任何评论已经足以推动运行时间> 30秒。

人们在真实数据存储支持的JDO应用程序中如何处理这些问题? (或者他们?)

有没有人在这种(很常见)的情况下从JDO/Datastore中提取了令人满意的性能?

-Bosh

回答

3

首先,对于那些经常访问(如用户)的对象,我靠的内存缓存。这应该会加快你的应用程序的速度。

如果你必须去数据存储,正确的方法是通过getObjectsById()。不幸的是,它看起来像GAE doesn't optimize this call。然而,在密钥的查询optimized在一次旅行到数据存储中提取所有的对象,所以这是你应该使用什么:

List myFriendKeys = fetchFriendKeys(); 
Query query = pm.newQuery(User.class, ":p.contains(key)"); 
query.execute(myFriendKeys); 

你也可以依靠低级别的API get()接受多个键,或者像我一样使用objectify

完全不同的方法是在列表属性上使用相等过滤器。如果列表中的任何项目匹配,这将匹配。因此,如果您的用户实体中有friendOf列表属性,则可以发出一个查询friendOf == theUser。你可能想要检查一下:http://www.scribd.com/doc/16952419/Building-scalable-complex-apps-on-App-Engine

+0

除非AppEngine支持对Collection字段的contains()调用,否则看起来您有最佳解决方案。 – Gunslinger47 2010-04-17 07:45:37

0

Facebook拥有28TB的内存缓存......但是,500次访问memcached也不是很便宜。它不能用来存放一大堆小件物品。 “Denomerization”是关键。这样的应用程序不需要支持临时查询。直接针对少数支持的查询计算并存储结果。

对于您的情况,您可能只有1种查询类型 - 返回此数据,以及应在用户页面上显示的其他数据。你可以预先计算这个混乱的大球,所以稍后一个基于userId的查询可以获取所有这些。

当userA向userB发表评论时,您检索userB的大混乱球,插入userA的评论并保存它。

当然,这种方法存在很多问题。对于大型互联网公司来说,他们可能没有选择,通用查询引擎不会削减它。但对于其他人?如果你可以使用旧的RDBMS,你会不会更高兴?

1

不幸的是菲利普的建议

Query query = pm.newQuery(User.class, ":p.contains(key)"); 

仅通过优化主键搜索时,使单个查询。例如,通过十个非主键值的列表,会给出以下跟踪 alt text http://img293.imageshack.us/img293/7227/slowquery.png

我希望能够批量获取来自所有用户的朋友的评论。如果我为每个用户存储列表,则此列表的长度不能超过1000个元素(如果它是用户的索引属性),如http://code.google.com/appengine/docs/java/datastore/overview.html中所述。

似乎越来越像我在这里使用了错误的工具集。

-B

2

以最小化DB读取。对于任何GAE项目而言,这都是一个重要的焦点 - 其他任何事情都会让你付出代价要做到这一点,尽可能预先计算,尤其是经常读取的信息。为了解决阅读500个朋友名字的问题,考虑你可能会改变朋友列表的次数远远少于阅读它,所以在每次更改时,将所有名称存储在一个可读取的结构中。

如果你绝对不能那么你必须手动调整每个案例,使用低级API来执行批量获取。

而且,优化速度,而不是数据大小。使用额外的结构作为索引,以多种方式保存对象,以便尽可能快地读取对象。数据便宜,CPU时间不是。

相关问题