【问题标题】:Designing lookup table in DynamoDB在 DynamoDB 中设计查找表
【发布时间】:2018-07-30 19:42:13
【问题描述】:

我在 dynamodb 中设计了一个查找表时遇到了一些问题,但没有遇到 GSI 的问题。

我有一个对象 U,这个对象有 4 个(感兴趣的)属性。 Id、A、B 和 C。我有另一个对象 T,它有 2 个(感兴趣的)属性 Id 和一个 U.Id 列表。

我需要创建一个 DynamoDB 表,我可以在其中进行快速查找,例如。

给定 T.Id,给我所有具有 A 的 U 对象,或给定 T.Id,给我所有具有 B 的连接 U 对象。最后给定 U.Id,给我具有 U 的 T.Id。 ID 在它的列表中。

我在想什么

| T.Id | Sort Key | U.Id | U.A | U.B | U.C |
| T1   | U1       | U1   | abc | rew | bgt |
| T1   | U2       | U2   | bgf | red | bcs |
| T2   | U3       | U3   | abc | rew | bgt |

T.Id 是 Primary Key,Sort Key 是 U.Id。 然后是 U.ID、U.A、U.B 和 U.C 上的 GSI。

这种方法现在应该可行,但我仅限于 5 GSI,而且我知道稍后会添加更多 U 属性。 T 在其列表中最多可以有 2000 个 U.Id。

我应该如何进行这种 DynamoDB 设计以实现最快的查找并且不会遇到 GSI 限制问题?

在给定 T.Id、U.A 和 U.B 的情况下获取所有 U.Id 会很好支持,但不是必需的,我可以要求此表的用户执行多个调用的交集。

【问题讨论】:

    标签: amazon-dynamodb


    【解决方案1】:

    我的解决方案的想法是花费空间复杂度来降低时间复杂度。

    创建一个表,hash key应该是U.id或者T.id,前缀为'U.'或“T.”,然后我们将范围键称为查找。 Lookup 列应该是一个合成键,如果要设置 T.Id 到 U.Id 的查找,则查找键的前缀是 'id.',如果查找是 T.Id 到 A,则查找键的前缀是'A'。后缀为 U.Id,与 B 和 C 相同。
    属性 A,B,C 应该只存储在 id 和 lookup 都是 U.Id 值的记录中

    要允许 U.Id 引用回 T.Id,您应该为 Lookup 列创建 GSI。

    |Id  |Lookup     |Attributes|
    +----+-----------+----------+
    |U.Id|U.Id       |A,B,C     |
    |T.Id|id.value   |          |
    |T.Id|A.value:Id |          |
    |T.Id|B.value:Id |          |
    |T.Id|C.value:Id |          |
    
    1. 给定 T.Id(值为 'tid'),给我所有具有 A(值为 'a')的 U 对象 SELECT 'Lookup' FROM table WHERE Id = T.tid & Lookup.beginsWith('A.a'); 然后我们可以通过用':'拆分查找的值来获取所有U的id。然后使用batch get获取所有U的值
    2. B 和 C 的想法相同
    3. 最后给出 U.Id(值为 'uid'),给我 T.Id,它的列表中有 U.Id。
      SELECT 'Id' FROM table WHERE Lookup = id.uid;
      然后你就有了 T.Id

    希望我的回答可以帮助到你,如果你有任何问题,请告诉我。

    注意:我写的SQL只是伪代码,仅供大家参考。

    【讨论】:

    • 这是个好主意,也是我一直在想的,但是我想减少从表中删除时必须进行的调用量。我知道这不在原始帖子中,但是当我必须从表中删除时,我只会知道 T.Id 和 U.Id 而不是 A、B、C 值。
    • 我认为您可以先删除键为 {Id: U.Id, Lookup: U.Id } 和 {Id: T.Id, Lookup: id.value} 的记录。然后通过扫描表格并过滤无用的项目来定期清理剩余的项目。
    • 或者查询后删除A、B、C前缀记录,找不到对应U.id的记录。
    【解决方案2】:

    您所描述的是一对多的关系。阅读有关如何在 NOSQL 存储中为一对多关系建模的文章。

    为了不那么抽象,我假设 u=user 和 t=team。一个团队可以有很多用户。一位用户只能在一个团队中。

    对此进行建模的方法是使用两个表 - 一个用户表和一个团队表。请注意,如果 Teams 没有属性,则只需 user 表就足够了。

    用户表:

    分区键:用户 ID

    属性:A

    属性:B

    属性:C

    属性:TeamId

    用户表 GSI:

    分区键:团队 ID

    团队表:

    分区键:TeamId

    属性:X

    给定 T.Id,给我所有具有 A 的 U 对象

    使用 GSI 查询 User 表,分区键 = TeamId,在 A 上使用过滤表达式

    给定 T.Id,给我所有具有 B 的连接 U 对象

    使用 GSI 查询 User 表,分区键 = TeamId,在 B 上使用过滤器表达式

    最后给出 U.Id,给我 T.Id,它的列表中有 U.Id。

    使用主分区键在用户表上使用 GetItem

    @Yu-Huang 描述的解决方案是一个图节点实现。您可以在https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-adjacency-graphs.html

    上阅读有关 DynamoDB 的内容

    我不推荐这种实现方式。它适用于多对多关系,并且会在不需要的地方增加大量复杂性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-07
      • 2012-09-26
      • 1970-01-01
      • 2023-03-23
      • 2019-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多