グローバルセカンダリインデックスとローカルセカンダリインデックス
テーブルを複製せずに別のクエリパターンをサポートできるよう、GSI と LSI を追加します。
「グローバルセカンダリインデックスとローカルセカンダリインデックス」はCoddyKit上の無料AWS Solutions Architectレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAWS Solutions Architect学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AWS Solutions Architectコースには全4レッスンが含まれています。
セカンダリインデックスが存在する理由
DynamoDBのプライマリキーは、テーブル上で効率的にクエリできる唯一の経路を定義します。別の属性でアイテムを検索する必要がある場合、たとえばテーブルのパーティションキーがCustomerIdで、商品IDごとにすべての注文を検索したい場合、セカンダリインデックスがなければ高コストなScanを実行する必要があります。
セカンダリインデックスは、別のキーを中心に構造化したデータのコピーを別に保持し、自動的に更新することでこの問題を解決します。DynamoDBには、Global Secondary Indexes(GSI)とLocal Secondary Indexes(LSI)という2種類があり、それぞれトレードオフが異なります。
Global Secondary Index(GSI)の基本
Global Secondary Indexでは、ベーステーブルとは完全に異なるパーティションキー(および任意でソートキー)を定義できます。GSIは真にグローバルであり、ベーステーブルのすべてのパーティションにまたがります。GSIのパーティションキーとして定義した任意の属性を使って、GSIをクエリしアイテムを検索できます。
GSIにはベーステーブルとは独立したプロビジョンドスループットがあり(またはオンデマンドモードを継承し)、1つのテーブルに最大20個のGSIを作成できます。既存のテーブルに対しても、GSIはいつでも追加または削除できます。
# Create a table with a GSI on ProductId
aws dynamodb create-table \
--table-name Orders \
--attribute-definitions \
AttributeName=OrderId,AttributeType=S \
AttributeName=ProductId,AttributeType=S \
AttributeName=OrderDate,AttributeType=S \
--key-schema AttributeName=OrderId,KeyType=HASH \
--global-secondary-indexes '[
{
"IndexName": "ProductId-OrderDate-index",
"KeySchema": [
{"AttributeName": "ProductId", "KeyType": "HASH"},
{"AttributeName": "OrderDate", "KeyType": "RANGE"}
],
"Projection": {"ProjectionType": "ALL"},
"ProvisionedThroughput": {"ReadCapacityUnits": 10, "WriteCapacityUnits": 5}
}
]' \
--provisioned-throughput ReadCapacityUnits=10,WriteCapacityUnits=5Local Secondary Index(LSI)の基本
Local Secondary Indexはベーステーブルと同じパーティションキーを共有し、異なるソートキーを使用します。LSIが「ローカル」と呼ばれるのは、単一のパーティション(同じパーティションキーを持つアイテム)の範囲内だけをクエリするためです。そのため、特定の顧客の注文を異なる属性順で検索する用途に適しています。
LSIはテーブル作成時に定義する必要があり、後から追加または削除することはできません。1つのテーブルには最大5個のLSIを作成できます。LSIはベーステーブルのプロビジョンドキャパシティを共有するため、個別のスループットはありません。また、ベーステーブルとLSIのデータを合わせた、パーティションキーあたり10 GBのストレージ制限が適用されます。
# Create a table with an LSI (at creation time only)
aws dynamodb create-table \
--table-name Orders \
--attribute-definitions \
AttributeName=CustomerId,AttributeType=S \
AttributeName=OrderDate,AttributeType=S \
AttributeName=TotalAmount,AttributeType=N \
--key-schema \
AttributeName=CustomerId,KeyType=HASH \
AttributeName=OrderDate,KeyType=RANGE \
--local-secondary-indexes '[{
"IndexName": "TotalAmount-index",
"KeySchema": [
{"AttributeName": "CustomerId", "KeyType": "HASH"},
{"AttributeName": "TotalAmount", "KeyType": "RANGE"}
],
"Projection": {"ProjectionType": "ALL"}
}]' \
--billing-mode PAY_PER_REQUESTGSIとLSIの主な違い
試験対策として、両者を比較すると次のようになります。
- パーティションキー:GSIはベーステーブルと異なるキーを指定できますが、LSIはベーステーブルと同じキーでなければなりません
- ソートキー:どちらもベーステーブルとは異なるソートキーを指定できます
- 作成時期:GSIはいつでも作成できますが、LSIはテーブル作成時にのみ作成できます
- スループット:GSIは独自のスループットを持ちますが、LSIはベーステーブルと共有します
- 整合性:GSIの読み取りは結果整合性のみですが、LSIの読み取りでは強い整合性を指定できます
- 上限:GSIは最大20個、LSIは1テーブルあたり最大5個です
プロジェクションの種類
インデックスを作成するときは、どの属性をプロジェクション(コピー)するかを選択します。
- KEYS_ONLY:ベーステーブルの主キーとインデックスキーのみを含めます。最も小さいインデックスですが、キー以外の属性には追加のGetItem呼び出しが必要です
- INCLUDE:キー属性に加えて、指定した追加属性を含めます。インデックスサイズとアクセスパターンのバランスを取れます
- ALL:すべての属性をインデックスにプロジェクションします。最も柔軟ですが、ストレージコストと書き込みコストが高くなります
プロジェクションの種類は、クエリで実際に必要となる属性に基づいて選択してください。過剰なプロジェクションは書き込みのたびにWCUを無駄に消費し、プロジェクションが不足すると、インデックスに含まれない属性を取得するために追加のGetItem呼び出しが必要になります。
GSIへのクエリ
GSIへのクエリでは同じQuery APIを使用しますが、--index-nameパラメータを指定します。クエリはベーステーブルではなく、GSIのキー定義に対して実行されます。GSIへのクエリは常に結果整合性です。ベーステーブルへの書き込み後、GSIは非同期で更新されるため、短い遅延が発生することがあります。
ベーステーブルのアイテムにGSIのパーティションキー属性がない場合、そのアイテムはGSIにまったく含まれません(スパースインデックスパターン)。これは、アイテムの一部だけをインデックス化する強力な手法です。たとえば、GSIのパーティションキーがStatusであれば、ステータスがPENDINGの注文だけを対象にできます。
# Query the GSI for all orders for a product in 2026
aws dynamodb query \
--table-name Orders \
--index-name ProductId-OrderDate-index \
--key-condition-expression 'ProductId = :pid AND OrderDate BETWEEN :start AND :end' \
--expression-attribute-values \
'{":pid":{"S":"prod-abc"},":start":{"S":"2026-01-01"},":end":{"S":"2026-12-31"}}'スパースインデックスパターン
スパースインデックスは、GSIのパーティションキーに値を持つアイテムだけがDynamoDBによってGSIにプロジェクションされる仕組みを利用します。一部のアイテムだけが持つ属性をGSIのパーティションキーに指定することで、そのサブセットだけを含むインデックスを作成できます。
例として、Ordersテーブルで、未発送の注文だけがPendingShipmentDate属性を持つとします。PendingShipmentDateに対するGSIには自然に未発送の注文だけが含まれるため、テーブル全体をスキャンせずに保留中の注文をすべて検索できる、非常に効率的な方法になります。
GSIオーバーローディングによる書き込みシャーディング
GSIオーバーローディングは、高度なシングルテーブル設計手法です。1つのテーブルに異なるエンティティタイプを保存し、汎用的なGSIキー属性(例:GSI1PKとGSI1SK)に、アイテムの種類に応じて異なる形式の値を設定します。これにより、1つのGSIを通じて、各エンティティタイプに専用の効率的なクエリ経路を持たせられます。
例として、UserアイテムにはGSI1PK = 'COUNTRY#US'およびGSI1SK = usernameを設定し、OrderアイテムにはGSI1PK = 'STATUS#PENDING'およびGSI1SK = orderDateを設定します。適切なプレフィックスを使ってGSIをクエリすると、目的のエンティティタイプを効率的に取得できます。
インデックスのスロットリングとキャパシティ
GSIのスロットリングは、ベーステーブルとは独立して発生します。GSIに設定されたWCUが少なすぎると、GSIにプロジェクションされるアイテムへの書き込みは、ベーステーブルに十分なキャパシティがあってもスロットリングされます。各GSIについて、ConsumedWriteCapacityUnitsとThrottledRequestsを個別に監視してください。
よくある落とし穴は、GSIのキャパシティをベーステーブルより低く設定し、書き込みパターンが突然変化してGSIへの書き込み速度が増加したときにスロットリングが発生することです。これを避けるには、GSIでAuto Scalingを使用するか、On-Demandモードを選択してください。
GSIとLSIの使い分けと再設計の判断
SAA-C03試験に向けた判断基準は次のとおりです。
- まったく異なる属性でクエリする必要がある → GSI
- 同じパーティション内で別の順序に並べてクエリする必要があり、作成時点で要件が決まっている → LSI
- 別のソートキーに対して強い整合性のある読み取りが必要 → LSI(GSIは結果整合性のみのため、これが唯一の選択肢です)
- 10種類以上の異なるクエリパターンがある → 複数のテーブルを個別に作成するより、GSIオーバーローディングを使ったシングルテーブル設計を検討する
- 分析のためにすべてのアイテムを取得するだけでよい → DynamoDBが適切なデータベースかどうかを再検討する
GSIの削除とバックフィル
GSIはベーステーブルに影響を与えず、いつでも削除できます。既存のテーブルに新しいGSIを追加すると、DynamoDBはベーステーブルをスキャンしてインデックスを非同期でバックフィルします。大規模なテーブルでは、完了まで数分から数時間かかることがあります。バックフィル中も、ベーステーブルは読み取りと書き込みの両方で完全に利用できます。
バックフィルの進行状況は、コンソールまたはDescribeTable APIで、インデックスのIndexStatusフィールドを確認することで監視できます。バックフィル中はCREATING、完了するとACTIVEになります。ACTIVEになるまでGSIにクエリを実行しないでください。
# Check GSI status during backfill
aws dynamodb describe-table \
--table-name Orders \
--query 'Table.GlobalSecondaryIndexes[*].{Name:IndexName,Status:IndexStatus}'理解度チェック
このレッスンで扱ったAWS Solutions Architect(SAA-C03)の概念について、理解度を確認しましょう。
レッスンのまとめ
このレッスンでは、GSIは別のパーティションキーを提供し、いつでも追加できること、LSIはベーステーブルのパーティションキーを共有し、テーブル作成時に定義する必要があること、そしてプロジェクションの種類によってインデックスにコピーされる属性が決まることを学びました。GSIは、高度なクエリの柔軟性を実現するスパースインデックスパターンやオーバーローディングパターンにも対応しています。次はDynamoDB StreamsとGlobal Tablesについて学びます。
よくある質問
「グローバルセカンダリインデックスとローカルセカンダリインデックス」レッスンは無料ですか?
はい。「グローバルセカンダリインデックスとローカルセカンダリインデックス」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AWS Solutions Architectコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AWS Solutions Architectコースには全4レッスンが含まれています。
「グローバルセカンダリインデックスとローカルセカンダリインデックス」で何を学びますか?
テーブルを複製せずに別のクエリパターンをサポートできるよう、GSI と LSI を追加します。 ブラウザで直接実行するハンズオンコードでAWS Solutions Architectを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
AWS Solutions Architectを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのAWS Solutions Architectは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「グローバルセカンダリインデックスとローカルセカンダリインデックス」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このAWS Solutions Architectレッスンでコードを書いて実行できますか?
はい。すべてのAWS Solutions Architectレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- テーブル、アイテム、プライマリキー
- プロビジョンドキャパシティとオンデマンドキャパシティ
- グローバルセカンダリインデックスとローカルセカンダリインデックス
- DynamoDB Streams とグローバルテーブル