这个问题涉及使用app引擎和客观化的数据库设计。我想讨论将所有(或者说多个)实体放入单个“表”的方法的利弊。
假设我有两个实体的(非常简化的)数据模型:
class User {
@Index Long userId;
String name;
}
class Message {
@Index Long messageId;
String message;
private Ref<User> recipient;
}
乍一看,把它们放在同一个“桌子”中是没有意义的,因为它们完全不同。
但是让我们来看看当我想搜索所有实体时会发生什么。假设我想找到并返回符合某些搜索条件的用户和消息。在传统的数据库设计中,我要么做两个单独的搜索请求,要么在写入期间创建一个单独的索引“表”,我会冗余地重复字段,这样我以后可以在一个搜索请求中检索项目。
现在让我们来看看以下设计。假设我会使用一个存储所有内容的实体。数据存储区将如下所示:
Type | userId | messageId | Name | Message
USER | 123456 | empty | Jeff | empty
MESSAGE | empty | 789012 | Mark | This is text.
看看我想去哪里?我现在可以搜索一个名称,并在一个请求中找到所有用户和消息。我甚至可以添加一个索引字段,比如
@Index List index;
到“common”实体,不需要两次写入数据。
鉴于数据存储区的行为,它在搜索空的索引字段时永远不会返回记录,并将其与部分索引相结合,我还可以通过查询给定Type的唯一字段来获取用户或消息。 / p>
只要许多字段为空,存储长(非标准化)记录的成本不会高于存储单个记录的成本。
我看到了进一步的优势:
也可能存在缺点,例如缓存,但可能没有。我现在看不到这一点。
那里有人试图沿着这条路走下去,或者看到这种做法存在严重缺陷吗?
答案 0 :(得分:2)
这实际上是Google数据存储区的工作原理。您的所有实体(以及其他所有实体)都存储在一个大致相同的BigTable中:
{yourappid}/{key}/{serialized blob of your entity data}
索引存储在所有应用程序共享的三个BigTable中。在我对这个问题的回答中,我试着详细解释这一点:efficient searching using appengine datastore ancestor paths
所以,为了重新解释一下你的问题,让谷歌维持善良或者将自己保留在自己的财产中是否更好?
简短的回答是,让Google维护种类会使得查询所有种类更加困难,但可以更轻松地在一种类型中进行查询。自己维护伪类可以更容易地查询所有类型,但是在一种类型中查询更加困难。
当谷歌按照正常使用方式维护种类时,您已经理解了这一限制 - 无法对所有不同类型的属性进行过滤。另一方面,使用带有自己的描述符的单个Kind意味着每次查询时都必须添加一个额外的filter()子句:
ofy().load().type(Anything.class).filter("discriminator", "User").filter("name >", "j")
有时这些多过滤器查询可以通过zigzag合并来满足,但有些不能。甚至那些能够满足之字形的那些也不那么有效。事实上,这可以解释Z字形的特定退化情况 - 像识别器这样的低基数属性。
您最好的选择是仔细挑选您的共享种类。 Objectify使您更容易使用多态:https://code.google.com/p/objectify-appengine/wiki/Entities#Polymorphism
多态类型层次结构共享一个Kind(基类@Entity的种类); Objectify为您管理鉴别器属性,并确保ofy().load().type(Subclass.class)
之类的查询转换为正确的过滤操作。
我建议谨慎使用此功能。
答案 1 :(得分:1)
一个严重的缺点是索引:
你所做的每一个查询都会编写一个单独的索引来进行操作,然后你所做的所有写操作都需要写入所有这些表(没有理由,在很多情况下)。
我目前无法想到其他缺点,除了每个实体的兆兆限制(如果你有很多类型,有很多值,你可能会遇到这种情况,因为你最终有一大堆专栏)
没有提到你的ONE实体模型会有多大,以及你的代码可能会如何错综复杂地进行分类&#34;您的实体类型可能最终成为