DynamoDB 日期 GSI
DynamoDB date GSI
我有一个 DynamoDB table 存储一些程序的执行,它看起来像这样:
分区键
排序键
开始日期
...
程序名
执行-id (uuid)
YYYY-MM-DD HH:mm:ss
...
我对此有两种查询方案table:
- 按程序名称和执行 ID 查询(简单)
- 按开始日期范围查询,例如:从
2021-05-15 00:00:00
到2021-07-15 23:59:59
的所有执行
执行第二个查询的正确方法是什么?
我知道我需要创建一个 GSI 来执行此操作,但是这个 GSI 应该是什么样子的?
我正在考虑将 StartDate
属性拆分为两个,如下所示:
分区键
排序键
开始月年
开始日期
...
程序名
执行-id (uuid)
YYYY-MM
DD HH:mm:ss
...
所以我可以使用 StartMonthYear
作为分区键并使用 StartDayTime
作为排序键来定义 GSI。
这种方法的唯一问题是我必须在我的应用程序中编写一些额外的逻辑来识别我需要在请求的范围内查询的所有分区。例如:
如果范围是:2021-05-15 00:00:00
到2021-07-15 23:59:59
我需要查询 2021-05
、2021-06
和 2021-07
分区以及相应的 day/time 限制(本例中只有第一个和最后一个分区)。
这是正确的做法还是我完全错了?
如果您想要快速获取特定时间范围内的所有执行,而不管程序是什么,有几种方法可以解决这个问题。
最简单的解决方案是这样的设置:
PK
SK
GSI1PK
GSI1SK
StartDate
PROG#<name>
EXEC#<uuid>
ALL_EXECUTIONS
S#<yyyy-mm-ddThh:mm:ss>#EXEC<uuid>
yyyy-mm-ddThh:mm:ss
- PK 是基础的分区键 table
- SK 是基数的排序键 table
- GSI1PK 是全局二级索引 GSI1 的分区键
- GSI1SK 是全局二级索引 GSI1 的排序键
- Query by program name and execution id (easy)
还是很简单,根据<name>
的程序名和<uuid>
的uuid做一个GetItem
。
- Query by start date range, for example: all executions from
2021-05-15 00:00:00
to 2021-07-15 23:59:59
使用 KeyConditionExpression 查询 GSI1:PK = ALL_EXECUTIONS AND SK >= 'S#2021-05-15 00:00:00' AND SK <= 'S#2021-07-15 23:59:59'
。这将 return 给定时间范围内的所有执行。
但是:您还将构建一个热分区,因为您有效地将所有数据写入 GSI1 中的单个分区。
为避免这种情况,我们可以对数据进行一些分区,分区取决于您处理的执行次数。您可以选择年、月、日、小时、分钟或秒。
我们可以将 GSI1PK 设置为 StartDate 的一个子集,而不仅仅是 ALL_EXECUTIONS。
PK
SK
GSI1PK
GSI1SK
StartDate
PROG#<name>
EXEC#<uuid>
EXCTS#<yyyy-mm>
S#<yyyy-mm-ddThh:mm:ss>#EXEC<uuid>
yyyy-mm-ddThh:mm:ss
在这种情况下,您将有一个每月分区,即:每个月的所有执行都被分组。现在您必须对 DynamoDB 进行多次查询,然后再加入结果。
对于从 2021-05-15 00:00:00
到 2021-07-15 23:59:59
的查询范围,您必须在 GSI1 上执行这些查询:
- @GSI1:
GSI1PK=EXCTS#2021-05 AND GSI1SK >= S#2021-05-15 00:00:00
- @GSI1:
GSI1PK=EXCTS#2021-06
- @GSI1:
GSI1PK=EXCTS#2021-07 AND GSI1SK <= S#2021-07-15 23:59:59
您甚至可以将这些并行化,然后将结果连接在一起。
同样:您的分区方案取决于您一天中的执行次数以及您希望支持的最大查询范围。
这是一种冗长的说法,说明您的方法原则上是正确的,但您可以根据您的用例选择调整它。
我有一个 DynamoDB table 存储一些程序的执行,它看起来像这样:
分区键 | 排序键 | 开始日期 | ... |
---|---|---|---|
程序名 | 执行-id (uuid) | YYYY-MM-DD HH:mm:ss | ... |
我对此有两种查询方案table:
- 按程序名称和执行 ID 查询(简单)
- 按开始日期范围查询,例如:从
2021-05-15 00:00:00
到2021-07-15 23:59:59
的所有执行
执行第二个查询的正确方法是什么?
我知道我需要创建一个 GSI 来执行此操作,但是这个 GSI 应该是什么样子的?
我正在考虑将 StartDate
属性拆分为两个,如下所示:
分区键 | 排序键 | 开始月年 | 开始日期 | ... |
---|---|---|---|---|
程序名 | 执行-id (uuid) | YYYY-MM | DD HH:mm:ss | ... |
所以我可以使用 StartMonthYear
作为分区键并使用 StartDayTime
作为排序键来定义 GSI。
这种方法的唯一问题是我必须在我的应用程序中编写一些额外的逻辑来识别我需要在请求的范围内查询的所有分区。例如:
如果范围是:2021-05-15 00:00:00
到2021-07-15 23:59:59
我需要查询 2021-05
、2021-06
和 2021-07
分区以及相应的 day/time 限制(本例中只有第一个和最后一个分区)。
这是正确的做法还是我完全错了?
如果您想要快速获取特定时间范围内的所有执行,而不管程序是什么,有几种方法可以解决这个问题。 最简单的解决方案是这样的设置:
PK | SK | GSI1PK | GSI1SK | StartDate |
---|---|---|---|---|
PROG#<name> |
EXEC#<uuid> |
ALL_EXECUTIONS |
S#<yyyy-mm-ddThh:mm:ss>#EXEC<uuid> |
yyyy-mm-ddThh:mm:ss |
- PK 是基础的分区键 table
- SK 是基数的排序键 table
- GSI1PK 是全局二级索引 GSI1 的分区键
- GSI1SK 是全局二级索引 GSI1 的排序键
- Query by program name and execution id (easy)
还是很简单,根据<name>
的程序名和<uuid>
的uuid做一个GetItem
。
- Query by start date range, for example: all executions from
2021-05-15 00:00:00
to2021-07-15 23:59:59
使用 KeyConditionExpression 查询 GSI1:PK = ALL_EXECUTIONS AND SK >= 'S#2021-05-15 00:00:00' AND SK <= 'S#2021-07-15 23:59:59'
。这将 return 给定时间范围内的所有执行。
但是:您还将构建一个热分区,因为您有效地将所有数据写入 GSI1 中的单个分区。
为避免这种情况,我们可以对数据进行一些分区,分区取决于您处理的执行次数。您可以选择年、月、日、小时、分钟或秒。
我们可以将 GSI1PK 设置为 StartDate 的一个子集,而不仅仅是 ALL_EXECUTIONS。
PK | SK | GSI1PK | GSI1SK | StartDate |
---|---|---|---|---|
PROG#<name> |
EXEC#<uuid> |
EXCTS#<yyyy-mm> |
S#<yyyy-mm-ddThh:mm:ss>#EXEC<uuid> |
yyyy-mm-ddThh:mm:ss |
在这种情况下,您将有一个每月分区,即:每个月的所有执行都被分组。现在您必须对 DynamoDB 进行多次查询,然后再加入结果。
对于从 2021-05-15 00:00:00
到 2021-07-15 23:59:59
的查询范围,您必须在 GSI1 上执行这些查询:
- @GSI1:
GSI1PK=EXCTS#2021-05 AND GSI1SK >= S#2021-05-15 00:00:00
- @GSI1:
GSI1PK=EXCTS#2021-06
- @GSI1:
GSI1PK=EXCTS#2021-07 AND GSI1SK <= S#2021-07-15 23:59:59
您甚至可以将这些并行化,然后将结果连接在一起。
同样:您的分区方案取决于您一天中的执行次数以及您希望支持的最大查询范围。
这是一种冗长的说法,说明您的方法原则上是正确的,但您可以根据您的用例选择调整它。