问题描述
考虑到拥有单个表并在DynamoDB中使用尽可能唯一的分区键在整个分区中均匀分配项目的最佳实践,我陷入了一个问题。
说我的表存储诸如users
,items
和devices
之类的项目。我将每个项目的ID存储为分区键。每个ID都以其类型作为前缀,例如user-XXXX
,item-XXXX
和device-XXXX
。
现在的问题是如何只查询某种类型的对象?例如,我想检索所有users
,该怎么做?如果允许begin_with
运算符来使用分区键,那么我可以搜索前缀,但是分区键只允许 quality 运算符。 / p>
如果现在我将我的类型用作分区键,例如,将user
用作分区键,然后将user-id
用作排序键,则可以使用,但是只会产生几个分区键从而导致热键问题。创建多个表是一个坏习惯。
欢迎提出任何建议。
解决方法
这是一个很好的问题。我也很想听听其他人正在解决这个问题。
如果使用分区键<type>-<id>
存储数据,则支持访问模式“按ID检索项目”。您已经正确地注意到,您无法在分区键上使用begins_with
,从而使您无法获得明确的方式来收集该类型的项目。
我认为您在创建带有有意义的排序键的<type>
分区键(例如Users
,Devices
等)时是正确的。但是,由于您的项目在表格中分布不均匀,因此您可能会遇到热分区的情况。
解决热分区问题的一种方法是使用外部缓存,这将防止您的数据库每次被 击中。这会带来额外的复杂性,您可能不想引入到应用程序中,但这是一个选择。
您还可以选择在DynamoDB中的各个分区之间分布数据,从而有效地实现自己的缓存。例如,假设您有一个Web应用程序,该应用程序直接在主页上列出了“排名前10的设备”。您可以创建分区DEVICES#1
,DEVICES#2
,DEVICES#3
,...,DEVICES#N
,每个分区都存储前10个设备。当您的应用程序需要获取前10个设备时,它可以随机选择这些分区之一来获取数据。对于大到Users
的分区来说,这可能不起作用,但可以考虑使用一种非常简洁的模式。
进一步扩展此想法,您可以按一些其他有意义的指标(例如<manufactured_date>
或<created_at>
)对设备进行分区。这样可以在整个数据库中更均匀地分布您的Device
个项目。您的应用程序将负责查询所有分区并合并结果,但是您将减少/消除热分区问题。 AWS DynamoDB docs更深入地讨论了这种模式。
DynamoDB数据建模几乎没有一种适合所有方法的方法,这会使数据建模非常棘手!您的特定访问模式将决定哪种解决方案最适合您的情况。
,牢记拥有单个表并在分区之间均匀分配项目的最佳实践
快速突出显示这里提到的两件事。
- 绝对均匀地分配分区键是一种最佳实践。
- 从一般意义上讲,将记录保存在单个表中是为了避免像在关系数据库中那样进行标准化。换句话说,可以使用重复/冗余的信息来构建。因此,不一定要将所有可能的数据合并到一个表中。
现在的问题是如何只查询某种类型的对象?对于 例如,我想检索所有用户,该怎么做?
让我们假设您在此表中仅包含“用户”数据。这将允许检索所有用户吗?当然不会,除非有一个名为user的分区,其余分区在userid的排序键后面说。
创建多个表是一个坏习惯
我不认为因此拥有多张桌子被认为是不好的。如果我们像规范化表一样存储并且不得不使用JOIN来将数据收集在一起,那就不好了。
话虽如此,遵循哪种更好的方法呢?
- 根本的区别是首先要考虑在表设计中派生的查询。这甚至表明DynamoDB是否是正确的选择。例如,选择每个用户的要求对于DynamoDB来说可能完全是一个不好的用例。
- 查询模式将进一步建议什么是最好的分区键。之所以选择DynamoDB,是因为摄取量很高且写入几乎都是不变的?
- 我是否总是拥有分区键来执行需要执行的选择?
- 更新语句会是什么样子,它会再次具有分区键来执行更新吗?
- 我是否需要按其他列进一步过滤,这可以作为默认的排序顺序吗?
当您开始回答其中一些问题时,可能会出现一个更好的模型。