假设我有一个具有id
和timestamp
属性的用户表。我希望能够查询这两个参数。如果我正确理解文档,那么使用DynamoDB有两种方法:
- 使用
id
作为散列,timestamp
作为范围来定义散列+范围主键 - 使用
id
定义仅散列主键,并使用timestamp
定义全局辅助索引
每种方法的优点和缺点是什么?
定义一个hash+range主键,使用id作为hash,时间戳为范围。
通过使id
成为Hash Key
,使timestamp
成为Range Key
,您有效地创建了一个"复合主键"。
换句话说,DynamoDB模式将允许以下数据(注意,"john"重复了三次)
id (Hash) | timestamp (Range)
----------|-------------------------
john | 2014-04-28T07:53:29.000Z
john | 2014-04-28T08:53:29.000Z
john | 2014-04-28T09:53:29.000Z
mary | 2014-04-28T07:53:29.000Z
jane | 2014-04-28T07:53:29.000Z
您可以执行以下操作:
GetItem
基于id
(哈希密钥)+timestamp
(范围密钥)组合得到单个项Query
以获得等于id
(哈希密钥)的所有项目的列表
如果这不是您想要的,那么分别在id
和timestamp
上的hash+范围就不是您要寻找的。
使用id定义仅散列主键,并定义全局辅助密钥使用时间戳进行索引。
在id
上使用仅散列主键时,id
必须是唯一的。
id (Hash) | timestamp (GSI Hash Key)
----------|-------------------------
john | 2014-04-28T07:53:29.000Z
mary | 2014-04-28T07:53:29.000Z
jane | 2014-04-28T07:53:29.000Z
然后,通过仅在timestamp
上应用GSI
散列,您将能够查询特定timestamp
的ids
列表。
这种方法的优点是,它绝对是您用例的正确解决方案#1是范围密钥的误用(除非您打算在应用程序级别确保id
不重复,这可能是个坏主意)。
使用GSI
的缺点是:
每个表最多只能有5个DynamoDB Update Dec 2019-您现在可以为每个表创建多达20个GSI
,所以明智地选择您想要的索引GSI
,并可以通过请求进一步提高此软限制https://aws.amazon.com/about-aws/whats-new/2018/12/amazon-dynamodb-increases-the-number-of-global-secondary-indexes-and-projected-index-attributes-you-can-create-per-table/GSI
将花费您额外的钱,因为您需要将Provisioned Throughput分配给它GSI
最终是一致的,这意味着DynamoDB不能保证与表的哈希键相关的数据被写入DB的那一刻,数据的GSI
哈希键立即可用于查询。DynamoDB文档指出,这通常是即时的,但可能需要几秒钟的时间才能获得GSI
哈希密钥- 不能在
GSI
上执行GetItem
以获得基于其Hash Key
/Hash Key
+Range Key
的项目。您只能使用返回List
的Query
这个答案可能有一些用处,但你对实现它的两种方法是正确的
假设您使用id
作为哈希键,那么为了只使用时间戳检索项目,您需要一个全局辅助索引。您仍然可以将timestamp
作为范围键,这将非常有用,因为DynamoDB将使用它按id
对查询结果进行排序。
使用全局辅助索引的主要缺点是需要在表上提供额外的吞吐量。
我也有类似的兴趣,并考虑在时间戳的一部分(例如,天或小时)上创建一个二级索引作为HASH,Id作为RANGE,以允许针对特定时间片进行查询,但这将强制时间片内的所有记录都在索引的同一分区中。
为了能够查询最近的数据和历史数据,亚马逊建议采用多表设计方法-请参阅https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-time-series.html.