DynamoDB中的本地和全局索引之间的差异

时间:2014-01-27 13:07:50

标签: indexing amazon-dynamodb secondary-indexes

我很好奇这两个二级索引以及它们之间的差异。很难想象这是怎么回事。我认为,这将有助于更多的人而不仅仅是我。

7 个答案:

答案 0 :(得分:90)

本地二级索引仍然依赖于原始的哈希密钥。 当您提供具有散列+范围的表时,请将LSI视为散列+ range1,散列+ range2 ..散列+ range6。 您还可以再查询5个范围属性。 此外,只有一个预配置吞吐量。

全局二级索引定义了一个新范例 - 每个索引的不同哈希/范围键 这打破了每个表的一个散列键的原始用法。 这也是定义GSI时需要为每个索引添加预配置吞吐量并为其付费的原因。

有关差异的更多详细信息,请参阅GSI announcement

答案 1 :(得分:63)

以下是文档中的正式定义:

  

全局二级索引 - 具有散列和范围键的索引   与桌上的不同。全球二级指数是   被认为是“全局的”,因为对索引的查询可以跨越所有   表中的数据,跨越所有分区。

     

本地二级索引 - 与该哈希密钥具有相同哈希密钥的索引   表,但是不同的范围键。本地二级索引是“本地”   从某种意义上说,本地二级索引的每个分区都是作用域的   到具有相同散列键的表分区。

但是,差异远远超出了关键定义的可能性。下面列出了一些重要因素,这些因素将直接影响维护索引的成本和工作量:

  • 吞吐量:

本地二级索引会消耗表中的吞吐量。通过本地索引查询记录时,该操作将消耗表中的读取容量单位。在具有本地索引的表中执行写操作(创建,更新,删除)时,将有两个写操作,一个用于表另一个用于索引。这两个操作都将消耗表中的写入容量单位。

全局二级索引具有自己的预配置吞吐量,当您在具有全局索引的表中执行写操作(创建,更新,删除)时,查询索引时操作将消耗索引的读取容量将是两个写操作,一个用于表另一个用于索引*。

*在定义全球二级索引的预配置吞吐量时,请务必特别注意以下要求:

  

为了使表写入成功,提供吞吐量   表的设置及其所有全局二级索引必须   有足够的写入容量来容纳写入;否则,   写入表将受到限制。

  • 管理层:

只能在创建表时创建本地二级索引,无法将本地二级索引添加到现有表中,一旦创建了无法删除它的索引,也无法创建。

创建表并添加到现有表时,可以创建全局二级索引,也允许删除现有的全局二级索引。

  • 阅读一致性:

本地二级索引支持最终或强一致性,而全局二级索引仅支持最终一致性。

  • 投影:

本地二级索引允许检索未投影到索引的属性(尽管需要额外的成本:性能和消耗的容量单位)。使用全局二级索引,您只能检索投影到索引的属性。

关于定义为二级索引的键的唯一性的特殊考虑:

在本地二级索引中,范围键值对于给定的哈希键值不需要是唯一的,同样的事情适用于全局二级索引,键值(哈希和范围)不需要是唯一的。< / p>

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

答案 2 :(得分:27)

这些是索引可能的搜索:

  • By Hash
  • By Hash + Range
  • 通过哈希+本地索引
  • 按全球指数
  • 按全球指数+范围指数

表的哈希和范围索引: 这些是以前版本的Amazon AWS SDK的常用索引。

全局和本地索引: 这些是在表上创建的“附加”索引,以及表的现有散列和范围索引。 全局索引 类似于哈希。 范围索引 的行为与用于表的哈希的范围索引类似。 在代码中的实体模型中,必须以这种方式注释getter:

  • 对于全局索引:

    @DynamoDBIndexHashKey(globalSecondaryIndexName = INDEX_GLOBAL_RANGE_US_TS)
    @DynamoDBAttribute(attributeName = PROPERTY_USER)
    public String getUser() {
        return user;
    }
    
  • 对于与全局索引关联的范围索引:

    @DynamoDBIndexRangeKey(globalSecondaryIndexName = INDEX_GLOBAL_RANGE_US_TS)
    @DynamoDBAttribute(attributeName = PROPERTY_TIMESTAMP)
    public String getTimestamp() {
        return timestamp;
    }
    

此外,如果您通过全局索引读取表,则必须是最终读取(不一致读取):

queryExpression.setConsistentRead(false);

答案 3 :(得分:14)

这样做的一种方法是:

LSI - 允许您对单个哈希密钥执行查询,同时使用多个不同的属性来“过滤”或限制查询。

GSI - 允许您对表中的多个哈希密钥执行查询,但结果会导致额外的吞吐量。

表格类型及其工作原理的更详细分类如下:

仅限哈希

你可能已经知道了;哈希密钥本身必须是唯一的,因为写入已存在的哈希密钥将覆盖现有数据。

<强>哈希+范围

Hash-Key + Range-Key允许您拥有多个相同的Hash密钥,只要它们具有不同的范围密钥即可。在这种情况下,如果您写入已经存在的Hash-Key,但是使用该Hash-Key尚未使用的Range-Key,则会生成一个新项目,而如果一个具有相同Hash + Range组合的项目已经存在,它会覆盖匹配的项目。

另一种思考方式就像是带有格式的文件。只要格式(范围)不同,您就可以在同一文件夹(表)中拥有与另一个文件具有相同名称(哈希)的文件。同样,只要名称不同,您就可以拥有多个格式相同的文件。

<强> LSI

LSI与Hash-Key + Range-Key基本相同,并且在创建项目时遵循相同的规则,除了您还必须为LSI提供值之外;它们不能留空/ null。

说LSI是“Range-Key 2”并不完全正确,因为你不能拥有一个名为file.format.lsifile.format.lsi2的文件(使用我之前的文件和格式)。但是,您可以file.format.lsifile.format2.lsifile.format.lsifile2.format.lsi

基本上,LSI只是一个“过滤键”,而不是一个实际的Range-Key;您的基础哈希值和范围值组合必须仍然是唯一的,而LSI值根本不必是唯一的。查看它的更简单方法可能是将LSI视为文件中的数据。您可以编写代码,查找名为“PROJECT101”的所有文件,无论其fileFormat如何,然后读取内部数据以确定查询中应包含的内容以及省略的内容。这基本上就是LSI的工作原理(只是没有打开文件来读取其内容的额外开销)。

<强> GSI

对于GSI,您实际上是为每个GSI创建另一个表,但没有维护多个单独的表来反映它们之间的数据的麻烦;这就是他们花费更多吞吐量的原因。

因此,对于GSI,您可以指定fileName作为基础哈希密钥,将fileFormat指定为基本范围密钥。然后,您可以指定Hash密钥为fileName2且范围密钥为fileFormat2的GSI。然后,您可以根据需要在fileNamefileName2上进行查询,这与您只能在fileName上查询的LSI不同。

主要优点是您只需要维护一个表而不是2个表,并且无论何时写入主哈希/范围或GSI哈希/范围,其他(s)都将自动更新因此,您不能“忘记”使用多表设置更新其他表格。此外,更新一个之后和更新另一个之前没有连接丢失的可能性,就像多表设置一样。

此外,GSI可以“重叠”基础哈希/范围组合。因此,如果您想创建一个以fileNamefileFormat作为基础哈希/范围,filePriorityfileName作为GSI的表格,则可以。

最后,GSI哈希+范围组合不必是唯一的,而基础哈希+范围组合必须是唯一的。这是双/多表设置无法实现的,但与GSI一起使用。因此,在更新时,您必须为基本和GSI哈希+范围提供值;这些值都不能为空/空。

答案 4 :(得分:11)

另一种解释方法:LSI可帮助您对具有相同哈希键的项目执行其他查询。 GSI可以帮助您对“跨表”的项目执行类似的查询。非常有用。

如果您有用户个人资料表: unique-id,name,email。在这里,如果您需要使表格可以在名称,电子邮件上查询 - 那么唯一的方法是让它们成为GSI(LSI不会帮助)

答案 5 :(得分:1)

这篇文章给出了很好的解释:

https://aws.amazon.com/blogs/aws/now-available-global-secondary-indexes-for-amazon-dynamodb/

我无法评论这个问题,但在写入和读取性能方面哪个更好:

(表读写吞吐量为100的本地索引)或(读/写吞吐量为50的全局索引以及表的读/写吞吐量为50?)

我的用例不需要单独的分区键,因此本地索引应该足以满足所需的功能。

答案 6 :(得分:0)

GSI不能用于一致读取。

LSI可以用于一致读取,但是它们会将主分区大小限制为10GB。 LSI也只能在创建表时创建。