Amazon dynamodb 如何在DynamoDB中建模一对一、一对多和多对多关系

Amazon dynamodb 如何在DynamoDB中建模一对一、一对多和多对多关系,amazon-dynamodb,Amazon Dynamodb,在DynamoDB中对这些关系建模的最佳方法是什么 一对一关系 一对多关系 多对多关系 我多次看到这个问题的变化,我想我应该写一个问答 关键DynamoDB基础知识 在阅读本文之前,您应该了解: 每个DynamoDB表都有一个独特的 主键必须由组成,并且可以选择具有。同时具有分区键和排序键的主键是复合键 请求使用其唯一主键返回一个且仅返回一个项 A执行快速查找,并且必须指定一个且仅指定一个分区键。它可以返回多个项目 计算表中的每个项,并可能基于过滤器参数返回子集。在某些情况下,扫描是正确的选

在DynamoDB中对这些关系建模的最佳方法是什么

  • 一对一关系
  • 一对多关系
  • 多对多关系

我多次看到这个问题的变化,我想我应该写一个问答

关键DynamoDB基础知识 在阅读本文之前,您应该了解:

  • 每个DynamoDB表都有一个独特的
  • 主键必须由组成,并且可以选择具有。同时具有分区键和排序键的主键是复合键
  • 请求使用其唯一主键返回一个且仅返回一个项
  • A执行快速查找,并且必须指定一个且仅指定一个分区键。它可以返回多个项目
  • 计算表中的每个项,并可能基于过滤器参数返回子集。在某些情况下,扫描是正确的选择,但如果使用不当,扫描速度会很慢,成本也会很高
  • 全局次索引()与基表具有不同的分区键。把它想象成有两个保持同步的表(基表和GSI)。根据使用情况,GSI可能会使基表的成本翻倍
  • 本地二级索引()与基表具有相同的分区键,但排序键不同。可以将其视为对基表数据进行排序的另一种方式,但只能在分区键内进行排序。LSI不需要任何成本

一对一
我们可以模拟护照和人来展示这种关系。一本护照只能有一个所有者,一个人只能有一本护照

方法非常简单。我们有两个表,其中一个表应该有外键

护照表:

分区键:PassportId

护照持有人表:

分区键:PersonId

请注意,PersonId没有出现在passport表中。如果我们这样做,我们将有两个具有相同信息的地方(哪些护照属于哪个人)。这将导致额外的数据更新和潜在的一些数据质量问题,如果表不同意谁拥有哪个护照

然而,我们缺少一个用例。我们可以很容易地通过他们的人名查找一个人,并找到他们持有的护照。但是如果我们有护照,我们需要找到谁拥有它呢?在当前模型中,我们需要在Passport holder表上执行一次检查。如果这是一个常规用例,我们就不想使用扫描。要支持a,我们只需在Passport holder表中添加a即可:

护照持有人表GSI:

分区键:PassportId

现在,我们可以使用PassportId或PersonId快速、廉价地查找关系

还有其他的建模选项。例如,您可以有一个没有外键的“普通”Passport表和Person表,然后有一个简单地将Passortid和PersonId映射在一起的第三个辅助表。我不认为这是这种情况下最干净的设计,但如果你喜欢它,这种方法没有错。请注意,它们是多对多关系部分中辅助关系表的一个示例


一对多
我们可以为宠物和主人做模型来展示这种关系。宠物只能有一个主人,但主人可以有很多宠物

该模型看起来非常类似于一对一模型,因此我将重点讨论这些差异

宠物桌:

分区键:PetId

所有者表:

分区键:OwnerId

我们把外键放在many表中。如果我们以另一种方式进行,并将PetID放在Owner表中,则一个Owner项必须有一组PetID,这将使管理变得复杂

如果我们想找到宠物的主人,这很容易。我们可以做一个简单的步骤来归还宠物物品,它会告诉我们主人是谁。但另一方面更难——如果我们有一个主人ID,他们会拥有哪些宠物?为了节省我们必须在宠物桌上做一个测试,我们改为在宠物桌上添加一个GSI

宠物桌GSI

分区键:OwnerId

如果我们有一个OwnerId,我们想找到他们的宠物,我们可以在宠物表GSI上执行。例如,对Owner O1的查询将返回带有PetId P1和P2的项

你可能会注意到一些有趣的事情。表的主键必须是唯一的。这仅适用于基表。一个GSI主键,在本例中仅为

在DynamoDB表中,每个键值必须是唯一的。然而,关键是 全局二级索引中的值不需要唯一

另一方面,GSI不需要与基表具有所有相同的属性。如果仅将GSI用于查找,则可能希望仅投影GSI键属性


多对多
在DynamoDB中,有三种主要的方法来建模多对多关系。每个人都有长处和短处

我们可以用医生和病人的例子来模拟这种关系。一个医生可以有很多病人,一个病人可以有很多医生


多对多-选项1-辅助表
一般来说,这是我首选的方法,这就是为什么它会优先使用。其思想是创建没有关系引用的“普通”基表。然后,关系引用进入辅助表(每种关系类型一个辅助表——在本例中,只有医生和患者)

医生表:

分区键:DoctorId

患者表

分区键:PatientId

医生病人表(辅助表)

分区键:DoctorId

排序键:PatientId

医生病患表GSI

分区键:PatientId

排序键:DoctorId

有三张桌子,博士桌
╔════════════╦═══════╦════════════╗
║ PassportId ║ Pages ║   Issued   ║
╠════════════╬═══════╬════════════╣
║ P1         ║    15 ║ 11/03/2009 ║
║ P2         ║    18 ║ 09/02/2018 ║
╚════════════╩═══════╩════════════╝
╔══════════╦════════════╦══════╗
║ PersonId ║ PassportId ║ Name ║
╠══════════╬════════════╬══════╣
║ 123      ║ P1         ║ Jane ║
║ 234      ║ P2         ║ Paul ║
╚══════════╩════════════╩══════╝
╔════════════╦══════════╦══════╗
║ PassportId ║ PersonId ║ Name ║
╠════════════╬══════════╬══════╣
║ P1         ║ 123      ║ Jane ║
║ P2         ║ 234      ║ Paul ║
╚════════════╩══════════╩══════╝
╔═══════╦═════════╦════════╗
║ PetId ║ OwnerId ║ Type   ║
╠═══════╬═════════╬════════╣
║ P1    ║ O1      ║ Dog    ║
║ P2    ║ O1      ║ Cat    ║
║ P3    ║ O2      ║ Rabbit ║
╚═══════╩═════════╩════════╝
╔═════════╦════════╗
║ OwnerId ║ Name   ║
╠═════════╬════════╣
║ O1      ║ Angela ║
║ O2      ║ David  ║
╚═════════╩════════╝
╔═════════╦═══════╦════════╗
║ OwnerId ║ PetId ║ Type   ║
╠═════════╬═══════╬════════╣
║ O1      ║ P1    ║ Dog    ║
║ O1      ║ P2    ║ Cat    ║
║ O2      ║ P3    ║ Rabbit ║
╚═════════╩═══════╩════════╝
╔══════════╦═══════╗
║ DoctorId ║ Name  ║
╠══════════╬═══════╣
║ D1       ║ Anita ║
║ D2       ║ Mary  ║
║ D3       ║ Paul  ║
╚══════════╩═══════╝
╔═══════════╦═════════╦════════════╗
║ PatientId ║ Name    ║ Illness    ║
╠═══════════╬═════════╬════════════╣
║ P1        ║ Barry   ║ Headache   ║
║ P2        ║ Cathryn ║ Itchy eyes ║
║ P3        ║ Zoe     ║ Munchausen ║
╚═══════════╩═════════╩════════════╝
╔══════════╦═══════════╦══════════════╗
║ DoctorId ║ PatientId ║ Last Meeting ║
╠══════════╬═══════════╬══════════════╣
║ D1       ║ P1        ║ 01/01/2018   ║
║ D1       ║ P2        ║ 02/01/2018   ║
║ D2       ║ P2        ║ 03/01/2018   ║
║ D2       ║ P3        ║ 04/01/2018   ║
║ D3       ║ P3        ║ 05/01/2018   ║
╚══════════╩═══════════╩══════════════╝
╔═══════════╦══════════╦══════════════╗
║ PatientId ║ DoctorId ║ Last Meeting ║
╠═══════════╬══════════╬══════════════╣
║ P1        ║ D1       ║ 01/01/2018   ║
║ P2        ║ D1       ║ 02/01/2018   ║
║ P2        ║ D2       ║ 03/01/2018   ║
║ P3        ║ D2       ║ 04/01/2018   ║
║ P3        ║ D3       ║ 05/01/2018   ║
╚═══════════╩══════════╩══════════════╝
╔══════════╦════════════╦═══════╗
║ DoctorId ║ PatientIds ║ Name  ║
╠══════════╬════════════╬═══════╣
║ D1       ║ P1,P2      ║ Anita ║
║ D2       ║ P2,P3      ║ Mary  ║
║ D3       ║ P3         ║ Paul  ║
╚══════════╩════════════╩═══════╝
╔═══════════╦══════════╦═════════╗
║ PatientId ║ DoctorIds║  Name   ║
╠═══════════╬══════════╬═════════╣
║ P1        ║ D1       ║ Barry   ║
║ P2        ║ D1,D2    ║ Cathryn ║
║ P3        ║ D2,D3    ║ Zoe     ║
╚═══════════╩══════════╩═════════╝
╔═════════╦═════════╦═══════╦═════════════╦══════════════╗
║ Key1    ║ Key2    ║ Name  ║   illness   ║ Last Meeting ║
╠═════════╬═════════╬═══════╬═════════════╬══════════════╣
║ P1      ║ P1      ║ Barry ║ Headache    ║              ║
║ D1      ║ D1      ║ Anita ║             ║              ║
║ D1      ║ P1      ║       ║             ║ 01/01/2018   ║
╚═════════╩═════════╩═══════╩═════════════╩══════════════╝
╔═════════╦═════════╦═══════╦═════════════╦══════════════╗
║ Key2    ║ Key1    ║ Name  ║   illness   ║ Last Meeting ║
╠═════════╬═════════╬═══════╬═════════════╬══════════════╣
║ P1      ║ P1      ║ Barry ║ Headache    ║              ║
║ D1      ║ D1      ║ Anita ║             ║              ║
║ P1      ║ D1      ║       ║             ║ 01/01/2018   ║
╚═════════╩═════════╩═══════╩═════════════╩══════════════╝