

# 在 DynamoDB 中管理全局二级索引
<a name="GSI.OnlineOps"></a>

本节介绍如何在 Amazon DynamoDB 中创建、修改和删除全局二级索引。

**Topics**
+ [创建具有全局二级索引的表](#GSI.Creating)
+ [描述表的全局二级索引](#GSI.Describing)
+ [向现有表添加全局二级索引](#GSI.OnlineOps.Creating)
+ [删除全局二级索引](#GSI.OnlineOps.Deleting)
+ [在创建期间修改全局二级索引](#GSI.OnlineOps.Creating.Modify)

## 创建具有全局二级索引的表
<a name="GSI.Creating"></a>

要创建具有一个或多个全局二级索引的表，请使用 `CreateTable` 和 `GlobalSecondaryIndexes` 参数。为获得最高的查询灵活性，您可以为每个表创建最多 20 个全局二级索引（默认配额）。

您必须指定一个属性以充当索引分区键。您可以选择为索引排序键指定另一个属性。这些关键属性中的任何一个都不必与表中的关键属性相同。例如，在 *GameScores* 表（请参阅 [在 DynamoDB 中使用全局二级索引](GSI.md)），`TopScore` 和 `TopScoreDateTime` 都不是关键属性。您可以创建具有分区键 `TopScore` 以及排序键 `TopScoreDateTime` 的全局二级索引。您可以使用这样的索引来确定高分与玩游戏时间之间是否存在相关性。

每个索引键属性必须是标量类型 `String`、`Number` 或 `Binary`。（它不能是文档或集合。） 您可以将任何数据类型的属性投影到全局二级索引中。其中包括标量、文档和集。有关数据类型的完整列表，请参阅 [数据类型](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes)。

如果使用预置模式，必须提供索引的 `ProvisionedThroughput` 设置，包括 `ReadCapacityUnits` 和 `WriteCapacityUnits`。这些预置吞吐量设置与表的设置分开，但行为方式相似。有关更多信息，请参阅 [全局二级索引的预调配吞吐量注意事项](GSI.md#GSI.ThroughputConsiderations)。

 全局二级索引继承基表的读/写入容量模式。有关更多信息，请参阅 [在 DynamoDB 中切换容量模式时的注意事项](bp-switching-capacity-modes.md)。

**注意**  
 创建新的 GSI 时，请务必检查您选择的分区键在新索引的分区键值之间生成的数据或流量是否分布不均或缩小。如果发生这种情况，您可能会看到同时发生回填和写入操作并且会限制对基表的写入操作。该服务采取措施最大限度地减少这种情况的可能性，但不会深入了解与索引分区键、所选的预测或索引主键的稀疏程度相关的客户数据的形状。  
如果您怀疑新的全局二级索引可能出现分区键值中的数据或流量过窄或偏斜，请先考虑以下方面，然后再向操作重要的表添加新索引。  
最安全的方法是在应用程序驱动最少流量时添加索引。
请考虑在基表和索引上启用 CloudWatch Contributor Insights。这将为您提供有用的流量分布洞察。
 在整个过程中观察 `WriteThrottleEvents`、`ThrottledRequests` 和 `OnlineIndexPercentageProgress` CloudWatch 指标。根据需要调整预置的写入容量，以便在合理的时间内完成回填，而不会对正在进行的操作产生任何重大的节流影响。在索引回填过程中，`OnlineIndexConsumedWriteCapacity` 和 `OnlineThrottleEvents` 预计显示 0。
如果由于写节流而对操作产生影响，请准备取消索引创建。

## 描述表的全局二级索引
<a name="GSI.Describing"></a>

要查看表上所有全局二级索引的状态，请使用 `DescribeTable` 操作。响应的 `GlobalSecondaryIndexes` 部分显示表上的所有索引，以及各自当前状态 (`IndexStatus`)。

全局二级索引的 `IndexStatus` 为：
+ `CREATING`— 索引当前正在创建，但是还不能使用。
+ `ACTIVE`— 索引已准备就绪，应用程序可以对索引执行 `Query` 操作。
+ `UPDATING`— 索引的预置吞吐量设置正在更改。
+ `DELETING`— 索引当前正在删除，不能再使用。

当 DynamoDB 完成构建全局二级索引时，索引状态会从 `CREATING` 变为 `ACTIVE`。

## 向现有表添加全局二级索引
<a name="GSI.OnlineOps.Creating"></a>

要将全局二级索引添加到现有表，请使用 `UpdateTable` 操作和 `GlobalSecondaryIndexUpdates` 参数。您必须提供以下参数：
+ 索引名称。该名称在表的所有索引中必须唯一。
+ 索引的键架构。您必须为索引分区键指定一个属性；您可以选择为索引排序键指定另一个属性。这些关键属性中的任何一个都不必与表中的关键属性相同。每个架构属性的数据类型必须是标量：`String`、`Number` 或 `Binary`。
+ 从表投影到索引中的属性：
  + `KEYS_ONLY`— 索引中的每个项目仅包含表的分区键、排序键值以及索引键值。
  + `INCLUDE` – 除 `KEYS_ONLY` 中描述的属性外，二级索引还包括您指定的其他非键属性。
  + `ALL`— 索引包括源表中的所有属性。
+ 索引的预置吞吐量，由 `ReadCapacityUnits` 和 `WriteCapacityUnits` 组成。与表的预吞吐量设置是分开的。

您只能为每个 `UpdateTable` 操作创建一个全局二级索引。

### 索引创建的阶段
<a name="GSI.OnlineOps.Creating.Phases"></a>

将新的全局二级索引添加到现有表时，该表在构建索引期间继续可用。但是，新索引不可用于查询操作，直到其状态从 `CREATING` 变为 `ACTIVE`。

**注意**  
创建全局二级索引不会使用 Application Auto Scaling。增加 `MIN` Application Auto Scaling 容量不会缩短全局二级索引的创建时间。

DynamoDB 后台分两个阶段构建索引：

**资源分配**  
DynamoDB 分配构建索引所需的计算和存储资源。  
在资源分配阶段，`IndexStatus` 属性为 `CREATING`，`Backfilling` 属性为 false。使用 `DescribeTable` 操作检索表及其所有二级索引的状态。  
当索引处于资源分配阶段时，无法删除索引或删除其父表。您也无法修改索引或表的预置吞吐量。您无法在表上添加或删除其他索引。但是，您可以修改这些其他索引的预置吞吐量。

**回填**  
对于表中的每个项目，DynamoDB 根据其投影确定要写入索引的属性集合（`KEYS_ONLY`、`INCLUDE` 或 `ALL`）。然后，它将这些属性写入索引。在回填阶段，DynamoDB 会跟踪表中正在添加、删除或更新的项目。也会根据需要在索引中添加、删除或更新这些项目的属性。  
在回填阶段，`IndexStatus` 属性设置为 `CREATING`，`Backfilling` 属性为 true。使用 `DescribeTable` 操作检索表及其所有二级索引的状态。  
当索引处于回填状态时，您不能删除其父表。但是，您仍然可以删除索引或修改表及其任何全局二级索引的预置吞吐量。  
在回填阶段，一些违规项目的写入可能会成功，而另一些则会被拒绝。回填后，对违反新索引的键架构的项目的所有写入操作都将被拒绝。我们建议您在回填阶段完成后运行 Violation Detector 工具，以检测和解决可能发生的任何关键违规。有关更多信息，请参阅 [在 DynamoDB 中检测和纠正索引键违规](GSI.OnlineOps.ViolationDetection.md)。

当资源分配和回填阶段正在进行中时，索引位于 `CREATING` 状态。在此期间，DynamoDB 会对表执行读取操作。对于从基表中填充全局二级索引的读取操作，您不需要付费。

当索引构建完成后，其状态将更改为 `ACTIVE`。您不能 `Query` 或 `Scan` 索引，直到变为 `ACTIVE`。

**注意**  
某些情况下，DynamoDB 会因索引键冲突而无法将表中的数据写入索引。在以下情况下，可能会发生这种情况：  
属性值的数据类型与索引键架构数据类型不匹配。
属性的大小超出索引键属性的最大长度。
索引键属性具有空字符串或空二进制属性值。
索引键冲突不会干扰全局二级索引的创建。但是，当索引变为 `ACTIVE` 后，则索引中不存在违规键。  
DynamoDB 提供了一个独立的工具来查找和解决这些问题。有关更多信息，请参阅 [在 DynamoDB 中检测和纠正索引键违规](GSI.OnlineOps.ViolationDetection.md)。

### 向大型表添加全局二级索引
<a name="GSI.OnlineOps.Creating.LargeTable"></a>

构建全局二级索引所需的时间取决于几个因素，例如：
+ 表的大小
+ 表中有资格包含在索引中的项目数
+ 投影到索引中的属性数量
+ 在索引构建期间在主表上写入活动

如果要将全局二级索引添加到非常大的表中，则创建过程可能需要很长时间才能完成。要监控进度并确定索引是否具有足够的写入容量，请参阅以下 Amazon CloudWatch 指标：
+ `OnlineIndexPercentageProgress`

有关 DynamoDB 相关 CloudWatch 指标的更多信息，请参阅 [DynamoDB 指标](metrics-dimensions.md#dynamodb-metrics)。

**重要**  
在创建或更新全局二级索引之前，您可能需要将大量表加入允许列表。请联系 AWS Support 以将您的表加入允许列表。

回填索引时，DynamoDB 会使用内部系统容量从表中读取。这是为了最大限度地减少创建索引的影响，并确保您的表不会耗尽读取容量。

## 删除全局二级索引
<a name="GSI.OnlineOps.Deleting"></a>

如果您不再需要全局二级索引，可以使用 `UpdateTable` 操作删除。

您只能为每个 `UpdateTable` 操作删除一个全局二级索引。

删除全局二级索引时，对父表中的任何读取或写入活动都没有影响。删除过程中，您仍然可以修改其他索引上的预置吞吐量。

**注意**  
使用 `DeleteTable` 操作删除表时，会同时删除该表的全局二级索引。
将不会针对全局二级索引的删除操作向您的账户收取费用。

## 在创建期间修改全局二级索引
<a name="GSI.OnlineOps.Creating.Modify"></a>

在构建索引时，您可以使用 `DescribeTable` 操作确定它处于哪个阶段。索引的描述包括一个布尔属性 `Backfilling`，指示 DynamoDB 当前是否正在使用表中的项目加载索引。如果 `Backfilling` 为 true，则资源分配阶段已完成，索引现在正在回填。

在回填阶段，您可以删除正在创建的索引。在此阶段中，您无法在表上添加或删除其他索引。

**注意**  
对于作为 `CreateTable` 操作的一部分创建的索引，`Backfilling` 属性未显示在 `DescribeTable` 输出。有关更多信息，请参阅 [索引创建的阶段](#GSI.OnlineOps.Creating.Phases)。