

# 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>

1 つ以上のグローバルセカンダリインデックスを持つテーブルを作成するには、`CreateTable` オペレーションと `GlobalSecondaryIndexes` パラメータを使用します。最大限のクエリの柔軟性を得るために、テーブルごとに最大 20 個のグローバルセカンダリインデックス (デフォルトのクォータ) を作成できます。

インデックスパーティションキーとして機能する属性を 1 つ指定する必要があります。必要に応じて、インデックスソートキーに別の属性を指定できます。これらのキー属性のいずれも、テーブルのキー属性と同じである必要はありません。例えば、*GameScores* テーブル (「[DynamoDB のグローバルセカンダリインデックスの使用](GSI.md)」参照) では、`TopScore` も `TopScoreDateTime` もキー属性ではありません。パーティションキーとして `TopScore`、ソートキーとして `TopScoreDateTime` を使用して、グローバルセカンダリインデックスを作成できます。このようなインデックスを使用して、ハイスコアとゲームのプレイ時刻との間に相関があるかどうかを判定できる可能性があります。

各インデックスキー属性は、`String`、`Number`、または `Binary` タイプのスカラーである必要があります。(ドキュメントまたはセットは指定できません)。グローバルセカンダリインデックスには、任意のデータ型の属性を射影できます。これには、スカラー、ドキュメント、およびセットが含まれます。データ型の詳細なリストについては、「[データ型](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes)」を参照してください。

プロビジョニング済みモードを使用する場合は、インデックスに `ReadCapacityUnits` および `WriteCapacityUnits` で構成される `ProvisionedThroughput` 設定をする必要があります。これらのプロビジョニングされたスループット設定は、テーブルの設定とは別ですが、同様の動作をします。詳細については、「」を参照してください[グローバルセカンダリインデックスに対するプロビジョニングされたスループットに関する考慮事項](GSI.md#GSI.ThroughputConsiderations)

 グローバルセカンダリーインデックスは、基本テーブルから読み込み/書き込みキャパシティーモードを継承します。詳細については、「[DynamoDB でキャパシティモードを切り替える際の考慮事項](bp-switching-capacity-modes.md)」を参照してください。

**注記**  
 新しい GSI を作成する際、選択したパーティションキーが、新しいインデックスのパーティションキー値全体でデータやトラフィックの分散が不均一だったり、狭くなっているかを確認することが重要になります。この場合、バックフィル操作と書き込み操作が同時に発生し、ベーステーブルへの書き込みをスロットリングしている可能性があります。このサービスでは、このシナリオの可能性を最小限に抑えるための対策を講じていますが、インデックスパーティションキー、選択した射影、またはインデックスプライマリキーのスパース性について、カスタマーデータのインサイトを見える形で取得していません。  
新しいグローバルセカンダリインデックスで、パーティションキー値全体でデータやトラフィックの分散が狭められたり、歪められたりしている可能性がある場合は、運用上重要なテーブルに新しいインデックスを追加する前に、次の点を考慮してください。  
アプリケーションのトラフィック量が最も少ない時間帯にインデックスを追加するのが、最も安全な方法と言えます。
ベーステーブルとインデックスで CloudWatch Contributor Insights 有効にすることを検討してください。これにより、トラフィックの分散に関する貴重なインサイトが得られます。
 プロセス全体を通して、CloudWatch メトリクス `WriteThrottleEvents`、`ThrottledRequests`、および `OnlineIndexPercentageProgress` を表示します。必要に応じて、プロビジョニングされた書き込みキャパシティを調整し、進行中の操作に対してスロットリングによる大きな影響を与えることなく、適切な時間内にバックフィルを完了します。`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` パラメータを使用します。以下の情報が必要です。
+ インデックス名。名前は、テーブル内のすべてのインデックスにおいて一意である必要があります。
+ インデックスのキースキーマ。インデックスパーティションキーには 1 つの属性を指定する必要があります。必要に応じて、インデックスソートキーに別の属性を指定できます。これらのキー属性のいずれも、テーブルのキー属性と同じである必要はありません。各スキーマ属性のデータ型は、`String`、`Number`、または `Binary` のスカラーである必要があります。
+ テーブルからインデックスに射影される属性は以下の通りです。
  + `KEYS_ONLY` – インデックス内の各項目は、テーブルパーティションキーとソートキーの値、およびインデックスキーの値のみで構成されます。
  + `INCLUDE` – `KEYS_ONLY` の属性に加えて、セカンダリインデックスにその他の非キー属性が含まれるように指定できます。
  + `ALL` – インデックスには、ソーステーブルのすべての属性が含まれます。
+ インデックスのプロビジョニングされたスループット設定で、`ReadCapacityUnits` および `WriteCapacityUnits` で構成されます。これは、テーブルのプロビジョニングされたスループット設定とは異なります。

`UpdateTable` オペレーションについて作成できるグローバルセカンダリインデックスは 1 つだけです。

### インデックス作成のフェーズ
<a name="GSI.OnlineOps.Creating.Phases"></a>

新しいグローバルセカンダリインデックスを既存のテーブルに追加すると、インデックスの構築中もテーブルが使用可能になります。ただし、新しいインデックスは、そのステータスが `CREATING` から `ACTIVE` に変わるまでクエリオペレーションに使用できません。

**注記**  
グローバルセカンダリインデックスの作成では、Application Auto Scaling を使用しません。`MIN` Application Auto Scaling の容量を増やしても、グローバルセカンダリインデックスの作成時間は短縮されません。

その裏では、DynamoDB は 2 つのフェーズでインデックスを構築しています。

**リソース割り当て**  
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` に変わります。インデックスが `ACTIVE` になるまで、`Query` や `Scan` はできません。

**注記**  
場合によっては、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 サポートに連絡して、テーブルの許可リストを作成してください。

インデックスがバックフィルされている間、DynamoDB は内部システム容量を使用してテーブルから読み込みます。これは、インデックスの作成による影響を最小限に抑え、テーブルの読み込みキャパシティーが不足しないようにするためです。

## グローバルセカンダリインデックスの削除
<a name="GSI.OnlineOps.Deleting"></a>

グローバルセカンダリインデックスが不要になった場合には、`UpdateTable` オペレーションを使用して削除することができます。

グローバルセカンダリインデックスは、1 回の `UpdateTable` オペレーションで 1 つだけ削除できます。

グローバルセカンダリインデックスが削除されている間、親テーブルの読み込みまたは書き込みアクティビティに影響はありません。削除の進行中でも、他のインデックスでプロビジョニングされたスループットを変更できます。

**注記**  
`DeleteTable` アクションを使用してテーブルを削除すると、そのテーブルのすべてのグローバルセカンダリインデックスも削除されます。
アカウントではグローバルセカンダリインデックスの削除操作に対して課金されません。

## 作成時のグローバルセカンダリインデックスの変更
<a name="GSI.OnlineOps.Creating.Modify"></a>

インデックスが作成されている間は、`DescribeTable` オペレーションを使用して、どのフェーズにあるかを判断します。インデックスの説明に含まれているブール属性 `Backfilling` は、DynamoDB がテーブルから項目を含むインデックスを現在ロードしているかどうかを示します。`Backfilling` が true の場合、リソース割り当てフェーズは完了していて、インデックスがバックフィルされています。

バックフィルフェーズでは、作成中のインデックスを削除できます。このフェーズでは、テーブルの他のインデックスを追加または削除することはできません。

**注記**  
`CreateTable` オペレーションの一部として作成されたインデックスの場合、`Backfilling` 属性は `DescribeTable` 出力に現れません。詳細については、「[インデックス作成のフェーズ](#GSI.OnlineOps.Creating.Phases)」を参照してください。