跳转到主要内容
Chinese, Simplified

本节详细介绍分层数据模型设计概念,从设计原则、术语、原则开始,并定义用于在DynamoDB中存储组件数据的必要数据库属性。然后讨论了基表和全局二级索引(GSI)配置以及关键设计概念。最后,您可以看到在所有可用的汽车组件都存储在DynamoDB表中之后,基础表和GSI是什么样子的。

设计原则

作为最佳实践,最好定义设计原则。以下原则适用于本指南的用例。

  • 设计一个可扩展和健壮的系统。确保性能足够高,延迟足够低,以符合数据检索服务级别协议(SLA)。
  • 通过确保系统支持所有已识别的数据访问模式,遵守所有业务要求。
  • 通过使用高效的写、读和数据存储机制,降低运营成本。
  • 通过创建尽可能少的表和GSI,降低维护和操作复杂性。
  • 通过分离实体项并应用行级细粒度访问模式和其他常见安全措施,确保数据安全性和可访问性。

术语

本指南使用以下术语。

  • 分区键维护表内的数据分区和数据分片。
  • 排序键支持分区内细粒度的项目级数据访问。
  • 主键是DynamoDB中的唯一标识符。主键由分区键和排序键组成。
  • 基本表是存储数据的主要DynamoDB表。
  • 全局辅助索引(GSI)用于索引目的,以提供更快的数据查找。
  • 在GSI中,分区键和排序键可能与基表中的键不同。
    • 一次最多可以为单个DynamoDB表创建20个GSI。最大数量是AWS服务软限制。如果你需要更多的GSI,你可以要求增加。
    • 每个GSI单独存储数据。您必须分别分配读和写单元,这会产生额外的成本。
    • 每个GSI可以随时创建或销毁。创建或销毁GSI不会影响基表。
    • 我们建议使用GSI而不是本地辅助索引(LSI)进行索引。

设计原则

使用以下方法设计了示例用例数据模型:

  • 要有效地管理不同的实体,请使用DynamoDB单表设计模式。这意味着整个系统将有一个用于存储所有类型数据的DynamoDB表。
    • 单表设计使您能够更灵活地维护一对多和多对多数据关系,而无需在多个DynamicDB表中复制数据。
    • 使用单个表可降低维护复杂性和成本。
    • 要了解有关单表设计的更多信息,请参阅DynamoDB文档中的“使用AmazonDynamoDB创建单表设计”博客文章和管理多对多关系的最佳实践。
  • 为了在表分区内实现统一的数据分布,请使用更细粒度和分布式的属性作为分区键。有关更多信息,请参阅设计分区键以分配工作负载。
  • 为了更快、更高效地查询并克服热分区问题,请使用适当的GSI Sharding跨分区分发数据。本指南中的示例对GSI2分区密钥使用随机分区。
  • 对GSI1和GSI2中具有不同排序键的多个实体使用相同的分区键。
  • 使用复合排序键。
  • 使用两个GSI:
    • GSI1,用于使用ParentID索引数据,以便您可以使用父ID进行查询
    • GSI2,用于使用GraphId索引数据,以便您可以使用组件ID查询所有下级组件
  • 仅使用分区键查询基表GSI1和GSI2。如果您不知道分区键,则无法执行数据查询。
    • 我们建议在没有有力有效案例的情况下,不要在DynamoDB中使用SCAN操作。SCAN操作非常昂贵。
    • 如果您必须经常使用SCAN操作,我们建议您重新设计数据模型。
  • 仅限将数据插入基表。然后,GSI将以最终一致的方式自动同步。

定义属性

下一步是定义在DynamoDB表中存储组件信息所需的属性。每个属性用于在实体中存储键值对数据。实体可以包含任意数量的属性。我们建议使用较短的名称作为属性名称,因为在读取单元中将考虑属性的长度(字节大小)。对于本指南中的示例,定义了以下属性。

Attribute name

Description

ComponentId

每个组件的唯一标识符(例如,CM1、CM2)。

ParentId

父组件ID。例如,CM2的ParentID是CM1。

GraphId

图形或树标识符。此示例有一棵树,其中顶部组件是CM1。实际上,可以有多棵树。

Path

图中组件的路径。例如,CM8的路径是CM1|CM2|CM4|CM8。

设计基表、GSI和键

定义基表和全局辅助索引(GSI)的分区键。

  • 遵循键设计最佳实践,在本例中使用ComponentId作为基表的分区键。由于它是唯一的,ComponentId可以提供粒度。DynamoDB使用分区键的哈希值来确定物理存储数据的分区。唯一的组件ID生成一个不同的哈希值,这可以促进表内数据的分布。可以使用ComponentId分区键查询基表。
  • 要查找组件的直接子级,请创建一个GSI,其中ParentId是分区键,ComponentId是排序键。您可以使用ParentId作为分区键来查询此GSI。
  • 要查找组件的所有递归子级,请创建一个GSI,其中GraphId是分区键,Path是排序键。您可以通过使用GraphId作为分区键和排序键上的BEGINS_WITH(Path,“$Path”)运算符来查询此GSI。

DynamoDB表键配置

Partition key

Sort key

Mapping attributes

Base table

ComponentId

 

ParentIdGraphIdPath

GSI1

ParentId

ComponentId

 

GSI2

GraphId

Path

ComponentId

在表中存储组件

下一步是将每个组件存储在DynamoDB基表中。从示例树中插入所有组件后,将得到一个基本表,如下所示。

ComponentId

ParentId

GraphId

Path

CM1

 

CM1#1

CM1

CM2

CM1

CM1#1

CM1|CM2

CM3

CM1

CM1#1

CM1|CM3

CM4

CM2

CM1#1

CM1|CM2|CM4

CM5

CM2

CM1#1

CM1|CM2|CM5

CM6

CM3

CM1#1

CM1|CM3|CM6

CM7

CM3

CM1#1

CM1|CM3|CM7

CM8

CM4

CM1#1

CM1|CM2|CM4|CM8

CM9

CM4

CM1#1

CM1|CM2|CM4|CM9

CM10

CM5

CM1#1

CM1|CM2|CM5|CM10

您可以使用此基表通过使用组件ID来查找组件的信息。

基表中的数据形成顶层组件(CM1)的层次树。要在DynamoDB中生成可扩展树,请在顶级组件ID上附加POST-FIX,例如#N。在本例中,CM1的GraphId为CM1#N,其中N是0–N范围内的随机数。N值是根据树的大小定义的,用于GSI中正确的数据分布。这种POST-FIX有助于避免热分区问题,它支持使用多个客户端并行运行查询,这有助于减少查询包含100多个组件的大树时的响应时间。

因为本例中的树很小,所以本例使用N=1。这将创建一个单独的分区CM1#1来存储整个树。如果使用N=5,它将创建五个分区来存储该树。在这种情况下,您必须查询所有五个分区以检索所有组件。然后,您必须合并所有数据以获得最终结果。

Path值是通过使用管道(|)运算符串联祖先来生成的。例如,从顶部开始的CM5路径是CM1|CM2|CM5。

GSI1索引

要检查组件的所有直接子级,需要使用ParentId作为分区键,使用ComponentId作为排序键来创建索引。以下数据透视表表示GSI1索引。您可以使用此索引通过使用父组件ID检索所有直接的子组件。例如,您可以了解汽车(CM1)中有多少电池可用,或者模块(CM4)中有哪些电池可用。

ParentId

ComponentId

CM1

CM2

CM3

CM2

CM4

CM5

CM3

CM6

CM7

CM4

CM8

CM9

CM5

CM10

GSI2索引

以下数据透视表表示GSI2索引。它使用GraphId作为分区键,Path作为排序键进行配置。使用GraphId和排序键(Path)上的begins_with操作,可以在树中找到组件的完整谱系。

GraphId

Path

ComponentId

CM1#1

CM1

CM1|CM2

CM1|CM3

CM1|CM2|CM4

CM1|CM2|CM5

CM1|CM2|CM4|CM8

CM1|CM2|CM4|CM9

CM1|CM2|CM5|CM10

CM1|CM3|CM6

CM1|CM3|CM7

CM1

CM2

CM3

CM4

CM5

CM8

CM9

CM10

CM6

CM7

原文地址
https://docs.aws.amazon.com/prescriptive-guidance/latest/dynamodb-hierarchical-data-model/dynamo-db-data-model-design.html
本文地址
Article

微信

知识星球

微信公众号

视频号