【问题标题】:Complicated, costly many-to-many entity references复杂、昂贵的多对多实体引用
【发布时间】:2016-05-15 16:58:22
【问题描述】:

我有四种主要类型:帐户、公司、服务和地址。我希望在公司和服务实体之间共享地址实体。

  • 帐户:这是用户帐户(电子邮件、密码)
  • 公司:提供服务的企业(祖先:帐户)
  • 服务:由公司(祖先:公司)提供的服务
  • 地址:公司或服务(祖先:帐户)的地址(字段组:街道、城市、国家/地区)

挑战: 公司和服务实体可能有不同地址;毕竟,一家公司的地址不一定是获得其服务的地方。服务可能有许多地址,因为公司可能会设立不同的特许经营/销售点,以获取其服务。

我希望以这样一种方式对数据进行建模,即地址可以被公司或服务实体或两者引用。我试过这两种方法:

假设这是地址模型:

class Address(ndb.Model):
    street = ndb.StringProperty(required=True)
    city = ndb.StringProperty(required=True)
    country = ndb.StringProperty(required=True)

方法 1:在 Service 或 Company 中存储地址密钥列表

class Service(ndb.Model):
    title = ndb.StringProperty(required=True)
    addresses = ndb.KeyProperty(repeated=True)

class Company(ndb.Model):
    name = ndb.StringProperty(required=True)
    addresses = ndb.KeyProperty(repeated=True)

问题:对于服务或公司的每个页面视图,我都需要执行额外的查询来获取它们各自的地址。随着我们实体数量的增加,这将成为一个代价高昂的大问题。

方法 2:创建一个 AddressMapping 实体,在两个实体之间形成关系:

class Service(ndb.Model):
    title = ndb.StringProperty(required=True)
    addresses = ndb.KeyProperty(repeated=True)

class AddressMapping(ndb.Model):
    entity = ndb.StringProperty(required=True)  # service or company
    address = ndb.KeyProperty(repeated=True)

问题:如果服务被禁用/删除/修改,我们需要删除/修改所有伴随的 AddressMapping 实体,否则它们将被孤立。查看页面时仍需要其他查询。这似乎也很昂贵。

这是我想出的两种方法;他们看起来都很糟糕。关于如何改进这一点的任何想法?

【问题讨论】:

  • 为什么不将公司、服务和地址合并到一个实体中。
  • 以正确的方式(标准化)然后进行测试。如果您只关心性能,请在汇编中编写所有内容
  • 对我来说,公司和服务听起来像是某个超类的子类。但是我想不出那个超类的名字。如果您想到一个,请相应地编辑您的问题。

标签: google-app-engine database-design google-cloud-datastore data-modeling app-engine-ndb


【解决方案1】:

如果您在公司和服务模型中存储地址键,则不需要“额外查询来获取它们” - 您只需 get 所有您需要的地址实体即可。这既快速又便宜。

【讨论】:

  • 不太确定这个解决方案的“快速和便宜”。如果您通过键获取实体,它仍然是数据存储读取/查询。如果您需要多个(或所有)地址,则需要多个键查询,而不是单个过滤器查询。
  • (a) 当您有密钥时,您不需要任何查询。 (b) 每个实体 1 次读取是检索数据的最低成本。其他所有解决方案都会更昂贵。
【解决方案2】:

这是一个非常标准的数据存储问题。解决方案是非规范化。通过允许重复,您可以将问题分解为一对多的关系。所以在你的例子中:允许Address 重复并让每个Address 有一个父级,CompanyService。或者将您的 Address 实体拆分为两个(ServiceAddressCompanyAddress)。

当您现在修改ServiceCompany 时,您可以对地址进行简单的祖先查询,您只会得到相应的地址。

此方法假定您每秒更新 Address(或您拥有的任何其他实体)不会超过一次,因为您将遇到每秒 1 次写入和实体组。

【讨论】:

  • 绝对没有理由创建重复的地址实体。
  • 取决于可能存在的一致性要求。在键或 ID 列表之前,我更喜欢祖先,但这只是我的意见..
  • 当孩子总是属于一个父母时,子实体是一个不错的选择,这里不是这种情况。您必须非常小心地复制数据,因为您创建了一个复杂的逻辑(请记住在两个地方进行编辑/删除等)。在这种特殊情况下,这是完全没有必要的。
  • 没有参数。无论如何,这种说法是毫无意义的,因为这是一个要求和个人品味的问题。两种方法都有效;总会有一种方法比另一种方法更有效的情况。我真的不想构建假设场景来证明我的观点,所以我会让操作人员决定他最喜欢哪种方法。
猜你喜欢
  • 2011-12-06
  • 2010-10-08
  • 1970-01-01
  • 2016-01-31
  • 1970-01-01
  • 1970-01-01
  • 2012-08-27
  • 2012-01-26
  • 1970-01-01
相关资源
最近更新 更多