如何设计关键模式以每个应用程序只拥有一个DynamoDB表?

13
根据DynamoDB文档:https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-general-nosql-design.html,“在DynamoDB应用程序中,您应该尽可能少地维护表格。大多数良好设计的应用程序仅需要一个表。”
但是根据我的经验,由于分区键设计,您总是需要做相反的事情
让我们考虑下一个情况。我们有几个用户角色,例如“管理员”,“经理”,“工人”。管理员的常规工作流程是CRUD管理器数据,其中读取操作是获取所有管理器列表而不是一个管理器。对于经理也是同样,他会CRUD工人数据。对于这两种情况,我们只有两种关键字使用场景:
  • 获取所有项目的列表(项键无关紧要)
  • 使用其完整键与特定项目一起工作。

根据文档的强调,我们应该有一个均匀分布的分区键,因此不能选择用户角色,而应该使用用户ID。由于我们已经有了一些随机ID作为分区键,因此我们根本不需要排序键,因为它根本不起作用 - 我们只使用分区键部分就能访问到一个用户。此时,我们意识到对于每个R操作,需要扫描整个表格,然后通过用户角色来过滤结果,这是低效的。那么如何改进呢?非常自然的方法是-让我们为每种用户类型都拥有自己的表格!然后我们将从管理员API扫描经理列表,并从经理列表中扫描工人列表。

我使用 DynamoDB 已经一年了,但仍然无法理解它。对我来说,实际上,对于真实生活场景,排序键是你永远无法使用的东西(我唯一使用过它的真实情况是访问像“协议”这样属于两个不同类型用户的项目,所以主键为{ partition: "managerId", sort: "userId" },并且辅助全局索引为{ partition: "userId", sort: "managerId" },因此我可以有效地查询所有特定管理员协议列表或所有特定用户协议列表,只提供相应的管理员或用户 ID 进行查询。该方法在此文档中讨论:https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-adjacency-graphs.html)。
我觉得我根本不理解这个概念。如何才能以只使用一个 DynamoDB 表格来有效地使用提供的示例的键模式?

2
我认为 "在 DynamoDB 应用中,应该尽可能少地维护表格。大多数良好设计的应用程序只需要一个表格。" 这个说法非常可疑。对我来说,这听起来像是对 NoSQL 的极端概括。我不建议将其作为应用程序设计目标。根据您需要执行的查询类型,使用 DynamoDB 最有效的方式。 - Mark B
@MarkB 我找到了这篇文章,展示了如何使用一张表和多种技术,但我需要花费很多时间来理解他们在做什么:https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-modeling-nosql-B.html - Arsenii Fomin
1
我支持马克·B的评论。但这要加以适量的怀疑。我认为这是一种过度概括,实际情况与此相差很远。在许多情况下,将所有内容存储在一个表中会变成一个非常糟糕的想法。 - Mike Dinescu
我认为AWS声称大多数NOSQL存储设计应该只有一个表格的说法完全是胡扯。回答你的问题,你可以使用图形节点模式来实现单表格(https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-adjacency-graphs.html)。但是,采用这种设计会极大地影响你的应用程序代码,并可能导致你的存储和业务逻辑代码之间的不良对齐。 - F_SO_K
2
这个视频 - https://www.youtube.com/watch?v=HaEPXoXVf2k 来自2018年re:invent,可能有助于理解单表设计哲学。 - Deepak Rao
显示剩余2条评论
2个回答

1
在这种情况下,您需要的是全局二级索引(https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html),其中分区键是用户角色。这样,您就可以通过UserRoleIndex查询具有特定角色的所有用户,并借助于用户ID上的排序键,在该角色中单独选择一个特定用户。
或者,如果您从头开始使用新表,则可能根本不需要索引(除非您在删除用户时不知道其角色)。您可以使用“组合主键”(https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html#HowItWorks.CoreComponents.PrimaryKey),其中分区键和排序键与我上面建议的索引相同。
使用您在问题中使用的相同表示法,我建议{ partition: "userRole", sort: "userId" }

DynamoDB有时可能很难理解,而且确实存在传统SQL数据库更合适的情况。来自AWS re:Invent 2018的这个视频非常适合了解两者之间的区别: https://www.youtube.com/watch?v=HaEPXoXVf2k&feature=youtu.be

不过,在您的情况下,看起来您有一个非常清晰的访问模式,因此DDB适合您使用。


由于这是一个老问题,对我来说已经过时了。经过进一步的调查,我发现对于许多使用情况(当您有数百到数千个几KB项目,并且从未预计会有数百万个项目),您永远不会脱离单个分区。最后自动意味着考虑分区键的均匀分布没有意义。此外,为了能够按某个范围获取项目,我将在系统中的所有键中使用相同的常量值(完全忽略分区键),例如{ partition: 1,sort: timestamp }。 - Arsenii Fomin

0

你可以拥有一个类似的模式

user_id, role, <other columns>

在哪里

  • user_id = hash-key
  • role = GSI hash-key

这样,您可以通过查询GSI来读取并获取所有经理的列表

使用GSI,DynamoDb创建另一个表并维护它,因此您不需要维护多个表。

如果您有任何问题,请告诉我


请问您可以看一下 https://stackoverflow.com/questions/57522977/dynamodb-query-all-records-as-per-no-sql-design 并回答吗? - Bhargava

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接