0

我的整个职业生涯都在使用非规范化的关系数据库。为了实现一个单表设计,可以在类似“App Store”的个人项目上处理几个特定的​​访问模式,我很难忘记所有这些。

这是一个快速的 ERD。有一个由平台(iOS、Android)和捆绑标识符标识的 App 模型以及在创建新版本时使用的默认映射。每个 App 可以有 0 到多个版本,这些版本由版本号标识(这是一个连续的数值,并且在 App 的上下文中是唯一的)。一个版本具有 IsReleased 属性以及其他几个属性(如名称、发行说明、二进制路径等)。

访问模式

  1. 列出每个应用程序的最新版本。
  2. 列出给定平台的每个应用程序的最新版本。
  3. 列出 IsReleased 为 1 的每个应用程序的最新版本。
  4. 列出 IsReleased 为 1 的给定平台的每个应用程序的最新版本。
  5. 获取特定应用的最新版本。
  6. 获取 IsReleased 为 1 的特定应用的最新版本。
  7. 获取特定应用的所有版本。
  8. 获取 IsReleased 为 1 的特定应用的所有版本。
  9. 获取特定应用的默认属性。

我遇到了 1 到 4 的问题,这张桌子是我要去的地方。我很难使用 GSI,它会按排序顺序为我提供单个版本的所有应用程序项目。

PK sk 默认值 应用名称 版本 被释放 其他属性
app_ios_com.app.one defaults { ... json ... }
app_ios_com.app.one version_1 应用一 1 1
app_ios_com.app.one version_2 应用一 2 1
app_ios_com.app.one version_3 应用一 3 1
app_ios_com.app.two defaults { ... json ... }
app_ios_com.app.two version_1 应用二 1 1
app_ios_com.app.two version_2 应用二 2 0
app_ios_com.app.two version_3 应用二 3 0

例如,对于访问模式 1,我想要:

PK sk 默认值 应用名称 版本 被释放 其他属性
app_ios_com.app.one version_3 应用一 3 1
app_ios_com.app.two version_3 应用二 3 0

例如,对于访问模式 3,我想要:

PK sk 默认值 应用名称 版本 被释放 其他属性
app_ios_com.app.one version_2 应用一 3 1
app_ios_com.app.two version_1 应用二 1 1

我必须记住的一些数据限制:

  • 目前只有10到20个应用程序,但我需要能够支持数百个
  • 大多数应用程序将有 100 到 200 个版本,其中有 20 到 30 个发布版本。最大的应用程序有 1000 个版本,其中发布了 50 个。
  • 在后端,IsReleased 标志通常会从 0 切换到 1,但偶尔会从 0 切换到 1。
  • 平均版本项约为 2 KB。
  • IsReleased 为 1 的访问模式变化更频繁地使用。

我觉得解决方案就在我面前,但我不能指望它。

4

1 回答 1

0

TLDR; 想到的解决方案是排行榜模式,用于在单独的记录中缓存最新的应用程序版本。每当添加新版本时,DynamoDB Streams会将更改作为事件发送到 lambda,然后更新非规范化的最新记录。

注意:您出色的文章中缺少一条信息:您需要多久执行一次latest查询?如果不是很频繁,那么“扫描并完成”将适用于您当前的卷。如果答案是latest每分钟 1k 次查询,那就另当别论了。好消息是您的基本表格设计是可靠的。 Latest当出现性能/成本问题时,可以增量实施查询优化,而不会弄乱表设计。

非规范化最新版本

我们将保留最新版本的非规范化副本,这是另一种听起来很罪恶的DynamoDB 模式。当添加版本或更改发布状态时,流触发的 lambda 将使用更新 API 更新这些记录。如何存储最新版本信息?我们有几种选择:

  1. 将所有latest数据存储在带有地图属性的单例记录中{app1: {latest version copy}, app2: ...}。您可以将更多逻辑放入记录中以处理isReleased项目,或者简单地获取记录并在后端进行过滤。
  2. 使用每个应用程序一条记录的全球二级索引。每条记录都有“最新”的 GSI1PK 和 GSI1SK 的app_id. 记录具有与#1 中相同的信息。
  3. 用作 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

注意:如果您有高查询量和低基数,热分区可能是这些“排行榜”类型非正规化模式的问题。如果这成为一个问题,您可以通过保留每个“最新”记录的多个副本来解决它,例如,有 X 个随机查询的副本latest-copy1latest-copy2... Amazon使用计算后缀latest-copy3调用此模式分片。

于 2021-12-02T09:56:22.963 回答