2016-03-12 51 views
13

我需要保持iOS应用上的本地数据与DynamoDB表中的数据保持同步。的DynamoDB表是〜2K行,只有一个散列密钥(id),和以下属性:如何按日期查询DynamoDB(范围键),没有明显的散列键?

  • id(UUID)
  • lastModifiedAt(时间戳)
  • name
  • latitude
  • longitude

我目前正在扫描并通过lastModifiedAt筛选,其中lastModifiedAt大于应用程序的上次刷新日期,但我想这会变得很昂贵。

最好的answer我可以找到的是添加一个全局二级索引lastModifiedAt作为范围,但没有明显的GSI的散列键。

当需要使用GSI进行范围查询时,什么是最佳实践,但没有明显的散列键?或者,如果全面扫描是唯一的选择,是否有任何最佳实践来降低成本?

回答

6

虽然D.Shawley的回答帮我指出了正确的方向,它错过了GSI两个方面的考虑:

  1. 散列+范围必须是唯一的,但天+时间戳(他推荐的方法)将不一定是唯一的。
  2. 通过只使用一天作为散列,我需要使用大量的查询来获取自上次刷新日期(可能是几个月或几年前)以来每天的结果。

因此,这里是我采取的方法:用哈希键创建一个全球次级指数(GSI)为YearMonth

  • (例如,201508)和范围为id
  • 查询的GSI多次,自上次刷新日期以来每月查询一次。查询也通过lastModifiedAt > [given timestamp]过滤。
+0

请参阅我的回答以了解其他注意事项。问候。 – bsd

+3

我有和你一样的情况,来到同一个解决方案。感谢您在此发布此信息。一注:GSI不需要是唯一的:http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GuidelinesForGSI.html – ustroetz

2

您可以使用时间戳的“日”部分作为散列并使用完整的时间戳作为范围。

+0

由于散列键需要一个'eq'条件,我会那么需要为,因为应用程序的最后一次刷新已通过每天进行查询? (该应用程序在本地存储'lastRefreshedAt'时间戳)。看起来像这样会比扫描更昂贵。 –

+0

也许我可以将时间戳的“年份”部分存储为散列键?这将大大减少某人第一次打开他们的应用程序时所需的查询次数,比如使用“day”部分。此时,似乎范围键变得无关紧要,因为通过散列键查询将带来自lastRefreshedAt后更新的所有项目。 –

17

虽然Global Secondary Index似乎符合您的要求,任何企图包括timestamp相关的信息作为你的Hash Key的部分将很可能创造了被称为“热分区”,这是非常不可取的。

不均匀的访问将发生,因为最近的项目将以比旧的更频繁的方式来检索。这不仅会影响您的表现,还会使您的解决方案降低成本效益。

见一些细节从文档:

例如,如果表中有非常少量的大量访问 分区键值,甚至可能是单个非常频繁使用的 分区键值的,请求交通专注于分区的小数字 - 可能只有一个分区。如果工作负载为 严重不平衡,这意味着它不成比例地集中在一个或几个分区上,请求将无法达到预配置吞吐量级别的总体 。要充分利用DynamoDB 吞吐量,请创建表,其中分区键具有不同值的大数 ,并且请求的值相当均匀,因为 尽可能随机。

基于什么说明,id看来确实是你的Hash Key(亦称Partition Key)一个不错的选择,我不会改变,作为GSI键相同的方式工作,至于分区。作为一个单独的说明,当您通过提供整个Primary Key来检索数据时,性能会得到高度优化,所以我们应该尽力找到一个尽可能提供该解决方案的解决方案。

我建议创建单独的表来存储基于最近更新的主键。您可以根据最适合您的用例的粒度将数据分割成表格。例如,假设您想要按天分段更新:

a。您的每日更新可以使用以下命名约定存储在表格中:updates_DDMM

b。 updates_DDMM表将只有id的(另一个表的哈希键)

现在说最新的应用程序刷新日期是从2天前(04/07/16),你需要得到最近的记录,那么你需要:

i。扫描表updates_0504updates_0604以获取所有散列键。

ii。最后通过提交BatchGetItem所有获得的散列键,从主表中获取记录(包含纬度/经度,名称等)。

BatchGetItem速度超快,并会像没有其他操作一样完成工作。

人们可以争辩说,创建额外的表会增加成本,你的整体解决方案......嗯,跟你GSI基本上是复制你的表(如果你正在投影的所有字段),并补充说,额外费用为所有〜2K记录,被他们最近更新的或不...

似乎直觉创建表这样的,但它实际上是时间序列数据处理(从AWS DynamoDB文档)时,最好的做法:

[。 ..该应用程序可能会显示横跨在客户的最新数据更相关和您的 应用程序可以访问最新的项目更频繁,随着时间的 通过这些项目较少访问,最终上了年纪的项目表中的所有项目 不均匀访问模式很少访问 。如果这是一种已知的访问模式,那么在设计表模式时可以考虑到它 。取而代之的 存储在一个表中的所有项目,您可以使用多个表 存储这些项目。例如,您可以创建表来存储每月或每周数据 。对于表存储从最新 按月或按周,其中的数据访问率高的数据,要求更高 吞吐量和表中存储旧数据,你可以拨下来的 吞吐量和节省资源。

您可以通过将“热”项存储在一个表中,节省资源,其中 的吞吐量设置较高,另一个表中的“冷”项的吞吐量设置较低。您可以通过简单地删除 表删除旧的项目。您可以选择将这些表备份到其他存储 选项,如Amazon Simple Storage Service(Amazon S3)。删除 整个表是显著更有效的不是删除项目 一个接一个,正如你做 尽可能多的删除操作是把操作写入吞吐量基本翻倍。

来源: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GuidelinesForTables.html

我希望帮助。问候。

+1

这是一个伟大的建议。谢谢你对此的深思。考虑到访问基于时间的数据的复杂性,这让我怀疑RDS是否是更好的解决方案。 –

+1

请注意,BatchGetItem仅限于100个项目。 –