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