数据存储区设计 - 如何模拟有效的连接

时间:2011-10-21 08:06:15

标签: java google-app-engine google-cloud-datastore

我有一个关于Google数据库云数据存储的设计问题。让我用一个例子解释一下:

我有类似“文章”的实体,其中包含以下属性:

  • title
  • userId
  • ....
  • sumOfScore

SumOfScore应该是所有相关“得分”实体的总和,它们具有 属性如:

  • 条款ArticleID
  • 用户id
  • 评分

在伪SQL中:
    sumOfScore =从得分中选择总和(得分)得分.articleId = article.id

我看到了两种设计方法(使用Google的数据存储API):

1。)没有物品sumOfScore的文章;但总是查询:

这意味着:每次阅读文章时,我都需要对此特定文章进行查询以计算sumOfScore。 想象一下向用户显示的100篇文章的列表。这需要对数据库进行额外的100次查询,只是为了显示每篇文章的分数。

尽管如此:这是使用Relational-DB时的首选方式。没有冗余和良好的规范化。 使用SQL,您只需使用一个join-select来捕获所有数据。 但它对云数据存储感觉不合适。

2。)每当分数实体发生变化时计算sumOfScore:

这意味着:每当添加,删除或更改分数实体时,相关文章 更新sumOfScore属性。

优势:阅读文章时无需其他查询。 sumOfScore在实体本身是多余的。

缺点:每次更改分数时,都会有一个额外的查询和一个额外的写入(更新文章实体)。 sumOfScore可能与实际的Score实体不匹配(例如,通过DB-Console更改了值)

有什么比较有经验的人认为?这种情况是否有共同的最佳做法? 在幕后做JPA或JDO的是什么?

非常感谢

莫斯

2 个答案:

答案 0 :(得分:2)

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"

最后一种选择;就是使用SQL。 Its experimental and hot out of the oven (in relation to being used on GAE) but it might be worth looking into.

答案 1 :(得分:1)

Theres第三种可能不妥协的可能性。

您将分数视为文章的孩子,并在文章中保留 sumOfScore 。出于分类目的,该字段将派上用场。由于这两个类来自同一个实体组,因此您可以创建分数并更新事务中的文章。您甚至可以通过查询所有得分来查看父级是否为文章

这种方法的问题在于,您每秒只能更新一次实体5次。如果您认为自己的活动多于此(请记住,这只是对单个实体的限制而非限制表),您应该查看sharded counter tutorial或查看google io's video解释此问题。

编辑:

关于同一主题的讨论很充分:How does Google Moderator avoid contention?