java数据存储设计如何模拟高效连接
我有一个关于谷歌数据库云数据存储的设计问题。让我用一个例子来解释:
我得到了具有以下属性的“Article”类型的实体:
- 头衔
- 用户ID
- 李>
- sumOfScore
SumOfScore应该是所有相关“分数”实体的总和,这些实体具有 属性,如:
- 文章ID
- 用户ID
- 得分
伪SQL中的:
sumOfScore=从得分中选择总和(得分)。articleId=物品。身份证
我认为有两种可能性可以设计它(使用谷歌的数据存储API):
1。)没有物品的属性和核心;但查询始终为:
这意味着:每次阅读一篇文章时,我都需要对这篇特定的文章进行查询,以计算sumOfScore。 想象一下,向用户显示一个包含100篇文章的列表。这将需要对数据库进行额外的100次查询,以显示每篇文章的分数
尽管如此,在使用关系数据库时,这将是我首选的方法。没有冗余和良好的规范化。 使用SQL,您可以只使用一个连接选择来捕获所有数据。 但对于云数据存储来说,它感觉不太合适
2。)每当分数实体发生变化时,计算总和分数:
这意味着:无论何时添加、删除或更改分数实体,相关文章 更新sumOfScore属性
优点:阅读文章时不需要额外的查询。sumOfScore在实体本身上是冗余的
缺点:每次更改分数时,都会有一个额外的查询和一个额外的写入(更新文章实体)。sumOfScore可能与实际得分实体不匹配(例如,通过DB控制台更改值)
更有经验的人会怎么想?对于这种情况是否有共同的最佳实践? JPA或JDO的实现到底在做什么
非常感谢
莫斯
# 1 楼答案
The first thing I recommend you look into the GAE article about sharding counters
这是一篇来自GAE最佳实践的文章,涉及如何处理计数器/金额。这可能有点棘手,因为每次更新一个元素时,都必须使用逻辑随机选择一个碎片计数器;当你获取你的计数时,你实际上是在获取一组实体并求和它们。我已经走了这条路,但不会在这里提供关于我是如何做到这一点的代码,因为我还没有对它进行战斗测试。但是,如果你只是到处复制/粘贴示例分片代码,那么你的代码可能会很草率,因此,如果你决定这样做,那么就创建一个抽象的或类型化的计数器类来重用你的分片逻辑
另一种选择是使用模糊计数。这种方法使用memcache,以牺牲准确性为代价提供更好的性能
See the section here labeled "Transient and frequently updated data"
最后一种选择;就是使用SQLIts experimental and hot out of the oven (in relation to being used on GAE) but it might be worth looking into.
# 2 楼答案
还有第三种可能性是不会妥协的
你为文章的子项打分,并将汇总保存在文章中。出于排序目的,此字段将派上用场。由于这两个类来自同一个实体组,您可以在事务中创建分数,并更新文章。你甚至可以通过查询所有的分数来再次检查给定的文章是谁的父母
这种方法的问题在于,每秒只能更新实体5次。如果你认为你会有更多的活动(记住,这只是对单个实体的限制,而不是对entier表的限制),你应该查看sharded counter tutorial或查看google io's video解释这一点
编辑:
关于这个话题,这里有一个很好的讨论:How does Google Moderator avoid contention?