我需要将iOS应用上的本地数据与DynamoDB表中的数据保持同步。 DynamoDB表是大约2K行,只有一个散列键(id
),以及以下属性:
id
(uuid)lastModifiedAt
(时间戳)name
latitude
longitude
我目前正在lastModifiedAt
进行扫描和过滤,其中lastModifiedAt
大于应用的上次刷新日期,但我想这会变得很贵。
我能找到的最好answer是添加一个lastModifiedAt
作为范围的全局二级索引,但GSI没有明显的哈希键。
当需要使用GSI按范围查询时,最佳做法是什么,但没有明显的散列键?或者,如果完全扫描是唯一选项,是否有任何最佳做法可以保留降低成本?
答案 0 :(得分:27)
虽然Global Secondary Index
似乎符合您的要求,但任何将timestamp
相关信息作为Hash Key
的一部分包含在内的尝试很可能会创建所谓的“热门分区”,非常不受欢迎。
将发生不均匀访问,因为将以比旧旧项目更频繁的方式检索最新项目。这不仅会影响您的性能,还会降低您的解决方案的成本效益。
请参阅文档中的一些详细信息:
例如,如果一个表具有非常少量的大量访问 分区键值,甚至可能是一个非常大量使用的键值 分区键值,请求流量集中在少数 分区 - 可能只有一个分区。如果工作量是 严重失衡,意味着它不成比例地集中在 一个或几个分区,请求将无法实现整体 预配置吞吐量水平。要充分利用DynamoDB 吞吐量,创建分区键具有较大数字的表 不同的值,并且要求相当一致的值,如 尽可能随机。
根据陈述的内容,id
似乎确实是您Hash Key
(又名Partition Key
)的不错选择,我不会因为GSI键工作而改变它与分区相同的方式。作为单独的注释,当您通过提供整个Primary Key
来检索数据时,性能会得到高度优化,因此我们应该尽可能找到提供该解决方案的解决方案。
我建议创建单独的表来存储主键,具体取决于它们的更新时间。您可以根据最适合您的用例的粒度将数据分段到表中。例如,假设您希望按天分段更新:
一个。您的每日更新可以存储在具有以下命名约定的表中:updates_DDMM
湾updates_DDMM
表只有id
个(另一个表的哈希键)
现在说最新的应用刷新日期是2天前(04/07/16),您需要获取最近的记录,然后您需要:
我。扫描表updates_0504
和updates_0604
以获取所有哈希键。
II。最后通过提交带有所有获得的散列键的BatchGetItem
来从主表(包含lat / lng,名称等)中获取记录。
BatchGetItem
非常快,并且可以像其他操作一样完成工作。
有人可能会争辩说,创建额外的表会增加整体解决方案的成本......好吧,GSI
你基本上会复制你的表(如果你预测所有字段)并为所有字段增加额外费用〜2k记录,最近是否更新......
这似乎是反直觉创建这样的表,但它实际上是处理时间序列数据时的最佳实践(来自AWS DynamoDB文档):
[...]应用程序可能会在所有项目中显示不均匀的访问模式 在表格中,最新的客户数据与您的相关性更高 应用程序可能会更频繁地访问最新项目 通过这些项目访问较少,最终旧项目 很少访问。如果这是一种已知的访问模式,您可以接受它 在设计表模式时要考虑到这一点。代替 将所有项目存储在一个表中,您可以使用多个表 存储这些物品。例如,您可以创建要存储的表 每月或每周数据。对于存储最新数据的表 月或周,数据访问率高,请求更高 吞吐量和存储旧数据的表,您可以拨打 吞吐量和节省资源。
您可以通过在一个表中存储“热”项来节省资源 更高的吞吐量设置,以及另一个表中的“冷”项 较低的吞吐量设置您只需删除即可删除旧项目 表格。您可以选择将这些表备份到其他存储 Amazon Simple Storage Service(Amazon S3)等选项。正在删除 整个表比删除项目更有效 一个接一个,它基本上使您的写吞吐量翻倍 与put操作一样多的删除操作。
来源: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GuidelinesForTables.html
我希望有所帮助。问候。
答案 1 :(得分:9)
虽然D.Shawley的回答帮助我指出了正确的方向,但它错过了GSI的两个考虑因素:
因此,这是我采取的方法:
YearMonth
(例如201508
),范围为id
lastModifiedAt > [given timestamp]
进行过滤。答案 2 :(得分:6)
您可以使用时间戳的“日期”部分作为哈希值,并使用完整时间戳作为范围。