DynamoDB Table 设计:如何为一对多关系建模,我需要所有 "one" 项和 "many" 项中的一个按某些属性排序
DynamoDB Table Design: How do I model a one to many relationship where I need all of the "one" items and one of "many" sorted by some attribute
我的整个职业生涯都在处理非规范化关系数据库。为了实现一个单一的 table 设计,可以处理“App Store”之类的个人项目中的几个特定访问模式,我很难摆脱所有这些。
Here's a quick ERD. 有一个由平台(iOS、Android)和包标识符标识的 App 模型以及创建新版本时使用的默认映射。每个应用程序可以有 0 到多个版本,这些版本由版本号标识(这是一个连续的数值,在应用程序的上下文中是唯一的)。一个版本具有 IsReleased 属性以及其他几个属性(如名称、发行说明、二进制路径等)。
访问模式
- 列出每个应用程序的最新版本。
- 列出给定平台的每个应用程序的最新版本。
- 列出 IsReleased 为 1 的每个应用程序的最新版本。
- 列出 IsReleased 为 1 的给定平台的每个应用程序的最新版本。
- 获取特定应用的最新版本。
- 获取 IsReleased 为 1 的特定应用的最新版本。
- 获取特定应用的所有版本。
- 获取 IsReleased 为 1 的特定应用的所有版本。
- 获取特定应用程序的默认属性。
我在处理 1 到 4 时遇到了问题,这个 table 正是我要去的地方。我很难找到一个 GSI,它将给我所有的 app 项目,按排序顺序只有一个 version。
pk
sk
Defaults
App Name
Version
IsReleased
Other Attributes
app_ios_com.app.one
defaults
{ ... json ... }
app_ios_com.app.one
version_1
App One
1
1
app_ios_com.app.one
version_2
App One
2
1
app_ios_com.app.one
version_3
App One
3
1
app_ios_com.app.two
defaults
{ ... json ... }
app_ios_com.app.two
version_1
App Two
1
1
app_ios_com.app.two
version_2
App Two
2
0
app_ios_com.app.two
version_3
App Two
3
0
例如,对于访问模式 1,我想要:
pk
sk
Defaults
App Name
Version
IsReleased
Other Attributes
app_ios_com.app.one
version_3
App One
3
1
app_ios_com.app.two
version_3
App Two
3
0
例如,对于访问模式 3,我想要:
pk
sk
Defaults
App Name
Version
IsReleased
Other Attributes
app_ios_com.app.one
version_2
App One
3
1
app_ios_com.app.two
version_1
App Two
1
1
我必须记住的一些数据限制:
- 目前只有10到20个应用,但我需要能够支持数百个
- 大多数应用程序将有 100 到 200 个版本以及 20 到 30 个发布版本。最大的应用程序有 1000 个版本,其中 50 个已发布。
- 在后端,IsReleased 标志通常会从 0 切换到 1,但偶尔会从 0 切换到 1。
- 平均版本项约为 2 KB。
- IsReleased 为 1 的访问模式变体使用频率更高。
我觉得解决方案就在我面前,但我不能指手画脚。
TLDR; 想到的解决方案是 leaderboard pattern to cache the latest app versions in separate record(s). Whenever a new version is added, DynamoDB Streams 将更改作为事件发送到 lambda,然后更新非规范化的最新记录。
注意:您出色的文章中缺少一条信息:您需要多久执行一次 latest
查询?如果不是很频繁,那么“扫描完成”对于您当前的卷就可以了。如果答案是每分钟 1k latest
次查询,那就另当别论了。好消息是您的基本 table 设计很可靠。 Latest
可以在出现 performance/cost 问题时逐步实施查询优化,而不会扰乱 table 设计。
反规范化最新版本
我们将保留最新版本的非规范化副本,这是另一个听起来有罪的 DynamoDB pattern。当添加版本或更改发布状态时,流触发的 lambda 将使用更新 API 更新这些记录。如何存储最新版本信息?我们有几种选择:
- 将所有
latest
数据存储在具有地图属性 {app1: {latest version copy}, app2: ...}
的单例记录中。您可以将更多逻辑放入记录中以处理 isReleased
项,或者只需在后端获取记录和过滤器。
- 使用全球二级索引,每个应用有一条记录。每条记录都有“最新”作为
app_id
的 GSI1PK 和 GSI1SK。记录
与#1 中的信息相同。
- 用作 GSI,每个应用有多个记录。这样的事情似乎有效。例如,查询 #4 将使用
GSI1PK=Latest#Released AND begins_with(GSI1SI, "IOS")
GSI1PK GSI1SK
Latest app_ios_com.app.one
Latest IOS#app_ios_com.app.one
Latest#Released app_ios_com.app.one
Latest#Released IOS#app_ios_com.app.one
注意:如果您的查询量大而基数小,hot partitions may be a problem for these "leaderboard" type deormalised patterns. If this becomes a problem, you can address it by keeping multiple copies of each "latest" record, e.g. have X copies that are queried randomly latest-copy1
, latest-copy2
, latest-copy3
. Amazon calls this pattern sharding using calculated suffixes.
我的整个职业生涯都在处理非规范化关系数据库。为了实现一个单一的 table 设计,可以处理“App Store”之类的个人项目中的几个特定访问模式,我很难摆脱所有这些。
Here's a quick ERD. 有一个由平台(iOS、Android)和包标识符标识的 App 模型以及创建新版本时使用的默认映射。每个应用程序可以有 0 到多个版本,这些版本由版本号标识(这是一个连续的数值,在应用程序的上下文中是唯一的)。一个版本具有 IsReleased 属性以及其他几个属性(如名称、发行说明、二进制路径等)。
访问模式
- 列出每个应用程序的最新版本。
- 列出给定平台的每个应用程序的最新版本。
- 列出 IsReleased 为 1 的每个应用程序的最新版本。
- 列出 IsReleased 为 1 的给定平台的每个应用程序的最新版本。
- 获取特定应用的最新版本。
- 获取 IsReleased 为 1 的特定应用的最新版本。
- 获取特定应用的所有版本。
- 获取 IsReleased 为 1 的特定应用的所有版本。
- 获取特定应用程序的默认属性。
我在处理 1 到 4 时遇到了问题,这个 table 正是我要去的地方。我很难找到一个 GSI,它将给我所有的 app 项目,按排序顺序只有一个 version。
pk | sk | Defaults | App Name | Version | IsReleased | Other Attributes |
---|---|---|---|---|---|---|
app_ios_com.app.one |
defaults |
{ ... json ... } |
||||
app_ios_com.app.one |
version_1 |
App One | 1 | 1 | ||
app_ios_com.app.one |
version_2 |
App One | 2 | 1 | ||
app_ios_com.app.one |
version_3 |
App One | 3 | 1 | ||
app_ios_com.app.two |
defaults |
{ ... json ... } |
||||
app_ios_com.app.two |
version_1 |
App Two | 1 | 1 | ||
app_ios_com.app.two |
version_2 |
App Two | 2 | 0 | ||
app_ios_com.app.two |
version_3 |
App Two | 3 | 0 |
例如,对于访问模式 1,我想要:
pk | sk | Defaults | App Name | Version | IsReleased | Other Attributes |
---|---|---|---|---|---|---|
app_ios_com.app.one |
version_3 |
App One | 3 | 1 | ||
app_ios_com.app.two |
version_3 |
App Two | 3 | 0 |
例如,对于访问模式 3,我想要:
pk | sk | Defaults | App Name | Version | IsReleased | Other Attributes |
---|---|---|---|---|---|---|
app_ios_com.app.one |
version_2 |
App One | 3 | 1 | ||
app_ios_com.app.two |
version_1 |
App Two | 1 | 1 |
我必须记住的一些数据限制:
- 目前只有10到20个应用,但我需要能够支持数百个
- 大多数应用程序将有 100 到 200 个版本以及 20 到 30 个发布版本。最大的应用程序有 1000 个版本,其中 50 个已发布。
- 在后端,IsReleased 标志通常会从 0 切换到 1,但偶尔会从 0 切换到 1。
- 平均版本项约为 2 KB。
- IsReleased 为 1 的访问模式变体使用频率更高。
我觉得解决方案就在我面前,但我不能指手画脚。
TLDR; 想到的解决方案是 leaderboard pattern to cache the latest app versions in separate record(s). Whenever a new version is added, DynamoDB Streams 将更改作为事件发送到 lambda,然后更新非规范化的最新记录。
注意:您出色的文章中缺少一条信息:您需要多久执行一次 latest
查询?如果不是很频繁,那么“扫描完成”对于您当前的卷就可以了。如果答案是每分钟 1k latest
次查询,那就另当别论了。好消息是您的基本 table 设计很可靠。 Latest
可以在出现 performance/cost 问题时逐步实施查询优化,而不会扰乱 table 设计。
反规范化最新版本
我们将保留最新版本的非规范化副本,这是另一个听起来有罪的 DynamoDB pattern。当添加版本或更改发布状态时,流触发的 lambda 将使用更新 API 更新这些记录。如何存储最新版本信息?我们有几种选择:
- 将所有
latest
数据存储在具有地图属性{app1: {latest version copy}, app2: ...}
的单例记录中。您可以将更多逻辑放入记录中以处理isReleased
项,或者只需在后端获取记录和过滤器。 - 使用全球二级索引,每个应用有一条记录。每条记录都有“最新”作为
app_id
的 GSI1PK 和 GSI1SK。记录 与#1 中的信息相同。 - 用作 GSI,每个应用有多个记录。这样的事情似乎有效。例如,查询 #4 将使用
GSI1PK=Latest#Released AND begins_with(GSI1SI, "IOS")
GSI1PK GSI1SK
Latest app_ios_com.app.one
Latest IOS#app_ios_com.app.one
Latest#Released app_ios_com.app.one
Latest#Released IOS#app_ios_com.app.one
注意:如果您的查询量大而基数小,hot partitions may be a problem for these "leaderboard" type deormalised patterns. If this becomes a problem, you can address it by keeping multiple copies of each "latest" record, e.g. have X copies that are queried randomly latest-copy1
, latest-copy2
, latest-copy3
. Amazon calls this pattern sharding using calculated suffixes.