可查询未绑定的物品数量
Queryable unbound amount of items
我一直在思考查询未绑定数量的项目的可能策略。
例如,考虑一个论坛 - 您可以有任意数量的论坛 post 按主题分类。您需要至少支持 2 种访问模式:post 详细信息视图和 post 主题列表。
// legend
PK = partition key, SK = sort key
虽然很容易得到一个 post,但如果不扫描就无法有效地查询 post 的列表。
PK = postId
非常适合查询给定主题的所有 post,但它们都在同一分区(“热分区”)中。
PK = topic and SK = postId#addedDateTime
将项目存储在桶中,例如每天都有新桶。这会将大量逻辑推送到应用层并增加延迟。例如,如果您需要获得 10 posts,则必须查询今天的存储桶,如果存储桶包含的项目少于 10 个,则查询昨天的存储桶,等等。甚至不要让我开始分页。如果它跨越水桶,那可能是一场噩梦。
PK = topic#date and SK = postId#addedDateTime
所以我的问题是如何以“DynamoDB 方式”存储和查询未绑定的项目列表?
我认为你对你的选择有很好的理解。
我不能自称知道解决 DynamoDB 中这一特定问题的唯一正确方法™,但为了讨论起见,我会抛出一些想法。
While it's easy to get a single post, you can't effectively query a list of posts without a scan.
如果您的主键仅由 postId
组成(我将使用 POST#<postId>
以使其更易于阅读),则肯定会出现这种情况。 table 看起来像这样:
对于“获取 post 详细信息视图(又名通过 ID 获取 post)”访问模式,这将是 超级 高效。但是,我们还没有built-in 无法按主题访问一组 Post。接下来让我们试一试。
有几种方法可以对 Post 和主题之间的 one-to-many 关系进行建模。首先想到的是在 topic
字段上创建二级索引。从逻辑上讲,这看起来像这样:
现在我们可以使用高效的 query
操作按主题获取 Post 的项目集合。如果每个主题的 Post 数量增加,分页将对您有所帮助。这对于您的应用程序可能就足够了。为了便于讨论,我们假设它创建了一个热分区,并考虑我们可以引入哪些策略来减少问题。
一个选项
你说
Store items in buckets, e.g new bucket for each day.
这是个好主意!让我们将二级索引分区键更新为 <topic>#<truncated_timestamp>
,这样我们就可以在给定时间范围内按主题对 post 进行分组 (day/week/month/etc)。
我在这里做了一些事情:
- 引入了两个新属性来表示二级索引 PK 和 SK(分别为 GSIPK 和 GSISK)。
- 在分区键中引入了一个截断的时间戳来表示给定的月份。例如,
POST#1
和 POST#2
都在九月有一个 posted_at
时间戳。我将这两个时间戳截断为 2020-09-01
以表示整个 9 月(或任何对您的应用程序有意义的时间界限)。
这将有助于跨分区分布您的数据,减少热键问题。正如您正确注意到的那样,这将增加您的应用程序逻辑的复杂性 并且 增加延迟,因为您可能需要发出多个请求来检索足够的结果以满足您的应用程序需求。但是,在这种情况下,可能 是一个合理的权衡。如果增加的延迟是一个问题,您可以 pre-populate 一个分区来包含前 N 个月的主题讨论的结果(例如 PK = TOPIC_CACHE#<topic>
的列表属性包含 post前 N 个月的 ID)。
如果 TOPIC_CACHE
最终成为热分区,您始终可以使用计算后缀对分区进行分片:
您的应用程序在检索主题缓存时可能会在 1..N 之间随机 select TOPIC_CACHE。
有多种方法可以实现此访问模式,这些选项仅代表几种可能性。如果是我的应用程序,我会首先使用 Post 主题作为分区键创建二级索引。它最容易实现,并且让我有机会了解我的应用程序访问模式在生产环境中的执行情况。如果热键问题开始成为问题,我会更深入地研究某种缓存解决方案。
我一直在思考查询未绑定数量的项目的可能策略。
例如,考虑一个论坛 - 您可以有任意数量的论坛 post 按主题分类。您需要至少支持 2 种访问模式:post 详细信息视图和 post 主题列表。
// legend
PK = partition key, SK = sort key
虽然很容易得到一个 post,但如果不扫描就无法有效地查询 post 的列表。
PK = postId
非常适合查询给定主题的所有 post,但它们都在同一分区(“热分区”)中。
PK = topic and SK = postId#addedDateTime
将项目存储在桶中,例如每天都有新桶。这会将大量逻辑推送到应用层并增加延迟。例如,如果您需要获得 10 posts,则必须查询今天的存储桶,如果存储桶包含的项目少于 10 个,则查询昨天的存储桶,等等。甚至不要让我开始分页。如果它跨越水桶,那可能是一场噩梦。
PK = topic#date and SK = postId#addedDateTime
所以我的问题是如何以“DynamoDB 方式”存储和查询未绑定的项目列表?
我认为你对你的选择有很好的理解。
我不能自称知道解决 DynamoDB 中这一特定问题的唯一正确方法™,但为了讨论起见,我会抛出一些想法。
While it's easy to get a single post, you can't effectively query a list of posts without a scan.
如果您的主键仅由 postId
组成(我将使用 POST#<postId>
以使其更易于阅读),则肯定会出现这种情况。 table 看起来像这样:
对于“获取 post 详细信息视图(又名通过 ID 获取 post)”访问模式,这将是 超级 高效。但是,我们还没有built-in 无法按主题访问一组 Post。接下来让我们试一试。
有几种方法可以对 Post 和主题之间的 one-to-many 关系进行建模。首先想到的是在 topic
字段上创建二级索引。从逻辑上讲,这看起来像这样:
现在我们可以使用高效的 query
操作按主题获取 Post 的项目集合。如果每个主题的 Post 数量增加,分页将对您有所帮助。这对于您的应用程序可能就足够了。为了便于讨论,我们假设它创建了一个热分区,并考虑我们可以引入哪些策略来减少问题。
一个选项
你说
Store items in buckets, e.g new bucket for each day.
这是个好主意!让我们将二级索引分区键更新为 <topic>#<truncated_timestamp>
,这样我们就可以在给定时间范围内按主题对 post 进行分组 (day/week/month/etc)。
我在这里做了一些事情:
- 引入了两个新属性来表示二级索引 PK 和 SK(分别为 GSIPK 和 GSISK)。
- 在分区键中引入了一个截断的时间戳来表示给定的月份。例如,
POST#1
和POST#2
都在九月有一个posted_at
时间戳。我将这两个时间戳截断为2020-09-01
以表示整个 9 月(或任何对您的应用程序有意义的时间界限)。
这将有助于跨分区分布您的数据,减少热键问题。正如您正确注意到的那样,这将增加您的应用程序逻辑的复杂性 并且 增加延迟,因为您可能需要发出多个请求来检索足够的结果以满足您的应用程序需求。但是,在这种情况下,可能 是一个合理的权衡。如果增加的延迟是一个问题,您可以 pre-populate 一个分区来包含前 N 个月的主题讨论的结果(例如 PK = TOPIC_CACHE#<topic>
的列表属性包含 post前 N 个月的 ID)。
如果 TOPIC_CACHE
最终成为热分区,您始终可以使用计算后缀对分区进行分片:
您的应用程序在检索主题缓存时可能会在 1..N 之间随机 select TOPIC_CACHE。
有多种方法可以实现此访问模式,这些选项仅代表几种可能性。如果是我的应用程序,我会首先使用 Post 主题作为分区键创建二级索引。它最容易实现,并且让我有机会了解我的应用程序访问模式在生产环境中的执行情况。如果热键问题开始成为问题,我会更深入地研究某种缓存解决方案。