DynamoDB のグローバルセカンダリインデックス(GSI)

キーのないアクセスパターンごとに GSI を足し、書き込みコストが 3 倍になって目覚め、 強整合を想定したせいでインデックスから古い行をまだ読む。グローバルセカンダリ インデックスは AWS が維持してくれる第 2 のテーブルだ — 同じ課金ルール、結果整合の 読み取りのみ、すべてのベーステーブル put での書き込み増幅。

毎秒 100 書き込みの 1 KB アイテム、us-east-1 オンデマンドでは、インデックスなしで 書き込みは月 $164.25、GSI 1 つで $328.50、2 つで $492.75。足す各 ALL 射影 GSI が 書き込みスループットを買い直す。

読み終えたらできること

  • 2 つ目や 3 つ目のインデックスにコミットする前に GSI 書き込み増幅を見積もれる。
  • 特定のアクセスパターンに対して GSI 対 LSI 対フィルター式を選べる。
  • 結果が半分の RCU レートで結果整合であることを知りつつ GSI から読める。
  • 射影とクォータ上限を破らずにスパースキーとオーバーロードキーを設計できる。

読む順番

  1. GSI 対 LSI — 再パーティション化された読み取り対 同じハッシュの代替ソート。作成時ルールと 10 GB LSI コレクション上限。
  2. インデックス射影ALLKEYS_ONLYINCLUDE。ストレージと書き込みサイズのトレードオフ。
  3. スパースインデックス — 冷たい行でインデックス キーを省略し、ホットな部分集合だけがコピーされるようにする。
  4. キーのオーバーロード — 規律あるキー形で 複数のアクセスパターンを 1 つの GSI に詰める。
  5. GSI の結果整合 — read-your-writes の失敗と、ベーステーブル読み取りが必要な UI パターン。
  6. GSI がベーステーブルをスロットルする — プロビジョニング不足のインデックスキャパシティが親の書き込みをブロックする。
8 件中 0 件読了クイズ
DynamoDB の GSI と LSI
DynamoDB の GSI vs LSI — パーティションキー、整合性、キャパシティ、10 GB の違い、そしてどちらのセカンダリインデックスに手を伸ばすかのシンプルなルール。
初級読了 7 分
DynamoDB のインデックス射影
DynamoDB のインデックス射影 — KEYS_ONLY、INCLUDE、ALL が GSI や LSI に何をコピーするか、書き込みコストのトレードオフ、射影されない属性が読み取りを増やす理由。
中級読了 5 分
DynamoDB のスパースインデックス
DynamoDB のスパースインデックスは、そのキーを持つアイテムだけを GSI に保持させます — 大きなテーブルの小さなサブセットを最も安くクエリする方法。
中級読了 8 分
DynamoDB のキーオーバーロード
DynamoDB のキーオーバーロード — 汎用的な pk/sk という名前の下に多数のエンティティ型を格納し、型をキーの値にエンコードして、begins_with でそれぞれを切り出す。
上級読了 8 分
DynamoDB の GSI が結果整合性である理由
DynamoDB の GSI が結果整合性である理由 — 書き込み直後の読み取りで古い結果が返る落とし穴、その裏にある伝播の仕組み、そしてそれを前提に設計する方法。
中級読了 8 分
DynamoDB GSI がベーステーブル書き込みをスロットルする理由
プロビジョニング不足の DynamoDB GSI がベーステーブル書き込みをスロットルする理由 — GSI バックプレッシャー、ホットなインデックスパーティション、例外と直し方。
上級読了 7 分
DynamoDB のベクトル検索
DynamoDB がベクトル検索をネイティブ実行可能に。新しいベクトルインデックスをライブ計測 — レイテンシー、書き込み/検索ごとの課金、S3 Vectors の方が安くなる条件。
中級読了 15 分
理解度チェッククイズに挑戦
このセクションで学んだ内容を確認しましょう。

グローバルセカンダリインデックスとは?

GSI は、任意のトップレベル StringNumber、または Binary 属性から選んだ 独自のパーティションキーと任意のソートキーを持つインデックスだ。インデックスキーは テーブルのキーを含む必要はない。

DynamoDB がコピーを維持する。アイテムを put、update、delete すると、影響を受ける すべての GSI が非同期に更新される。インデックスへ直接書くことはない。インデックス名に 対する Query または Scan で読む。

Table: orders — PK on customer, GSI "status-placed" on status
fieldvaluenote
PK"CUST#9313"table partition key
SK"ORD#2026-08-01#K4"table sort key
status"SHIPPED"GSI partition key
placed"2026-08-01"GSI sort key

status-placed GSI を status = "PENDING" でクエリすると、すべての顧客にまたがる 保留中の注文を日付順で得る。ベーステーブルは Scan なしではそれに答えられない。

インデックスキー属性を欠くアイテムは、単にインデックスに存在しない。その隙間を スパースインデックス が利用し、巨大テーブルの 小さなホット部分集合を、それ自体の事前フィルターされたコレクションに変える。

GSI はいくらかかるか?

書き込み側が支配する。1 KB アイテムは 1 書き込み (書き込みは 1 KB ごとに切り上げ)で、 ALL 射影ならすべてのベーステーブル書き込みがすべての GSI へ繰り返される。 3 つの持続書き込みレートで計測:

持続書き込みGSI 0GSI 1GSI 2
10 writes/s$16.43/mo$32.85/mo$49.28/mo
100 writes/s$164.25/mo$328.50/mo$492.75/mo
1,000 writes/s$1,642.50/mo$3,285.00/mo$4,927.50/mo

最大 1 KB のアイテム、オンデマンド、us-east-1、AWS 公開の百万書き込みリクエスト ユニットあたり $0.625(2026-07-29 の料金同期)。10 writes/s は 730 時間の請求月で 2,628 万 WRU。

GSI 列は正確な倍数ではなく下限として読む。インデックスアイテムはベーステーブルの キー、インデックス自身のキー、約 100 バイトのオーバーヘッドを運ぶので、1 KB の線に近い ベースアイテムは各インデックスへ 1 ではなく 2 WRU を書く — ×2 と ×3 はそこから増える。

GSI キー値を変える更新は 2 回のインデックス書き込みを請求する — 古いエントリを 削除する 1 回と新しいものを put する 1 回 — なので揮発性のインデックスキーは 安定したものより高い。

ストレージも繰り返す。ALL 射影は us-east-1 で月 $0.25/GB(同じ同期)でテーブルを 再格納し、インデックスアイテムあたり 100 バイトのオーバーヘッドが加わる。10 GB の テーブルは GSI あたり月 $2.50 の追加だ。

KEYS_ONLY または INCLUDE に縮めると両方の請求が縮む。 インデックス射影 を参照。

プロビジョンドモードでは同じ増幅がキャパシティとして現れ、プロビジョニング不足の GSI がベーステーブルの書き込みをスロットルする。 なぜ GSI がベーステーブルの書き込みをスロットルするか がその失敗を歩く。

自分のワークロードを見積もるには、 料金計算機 が上の数字と同じ料金表で走る。

GSI が読み取りをどう課金するか

GSI の読み取りは常に で、結果整合の読み取りは 半額レートで課金される。4 KB あたり 0.5 RCU。

二十個の 1 KB アイテムを返す Query は合計 20 KB、五つの 4 KB ユニットに切り上げ、 2.5 RCU を請求する。同じ二十アイテムをベーステーブルから強整合で読むと 5 RCU。

半額はラグを買う。変更は GSI へ「通常条件では一瞬のうちに」(AWS の文言)伝播し、 それを待ち切る ConsistentRead オプションはない。

コードが自分の書き込みを GSI 経由で読み戻すなら、本番で刺さる前に なぜ GSI は結果整合か を読む。

GSI 対 LSI 対フィルター式

あなたのアクセスパターン手に取るものなぜ
テーブルキーではない属性でクエリするGSI再パーティション化する唯一のインデックス。ライブテーブルへいつでも追加できる
同じパーティション内の第 2 ソート順、強整合読み取りLSIテーブルキャパシティを共有し ConsistentRead をサポート。作成時のみ、10 GB コレクション上限
巨大テーブルの小さなホット部分集合をクエリするスパース GSIインデックスキーを運ぶアイテムだけがコピーされ、インデックスが小さく安く保たれる
すでに安い 1 回の Query である結果セットを絞るフィルター式維持するコピーはないが、捨てる各アイテムを読む分は支払う
二度と聞かないワンオフの質問インデックスなしScan またはエクスポートは一度のコスト。インデックスは毎月コストがかかる

LSI の上限は聞こえるより厳しい。パーティションキー値あたり 10 GB はベーステーブル アイテムとそのキーを持つすべての LSI エントリを数え、コレクションがそれに達すると DynamoDB は書き込みを拒否する。

それと作成時のみのルールが、正直な既定が GSI である理由だ。 GSI 対 LSI が全体の論を立てる。

インデックス設計を形づくる上限

  • テーブルあたり 20 GSI: 既定クォータ。Service Quotas 経由で調整可能。
  • テーブルあたり 5 LSI: 固定で、CreateTable 時のみ。あとから追加できない。
  • 100 の射影属性: テーブルの全インデックスにまたがる INCLUDE 属性の合計。 KEYS_ONLYALL 射影はそれにカウントされない。
  • QueryScan のみ: GetItemBatchGetItem はどのセカンダリ インデックスでも動かない。
  • GSI からのベーステーブル取得なし: GSI クエリは射影された属性だけを返す。 LSI クエリは追加の読み取りコストで未射影属性を取得できる。
  • インデックスキーはトップレベルのスカラー: StringNumber、または Binary。セット、リスト、マップ、ネスト属性は不可。

稼働中のテーブルに GSI を追加する

LSI と違い、GSI はすでにトラフィックを捌いているテーブルにも追加できる。 UpdateTable は 1 回の呼び出しにつきインデックスの作成または削除を 1 つ受け付け、 その間テーブルは ACTIVE のままだ。DynamoDB は新しいインデックスを 2 つのフェーズで 構築する — まずインデックスのリソースが作られ、次にインデックスキー属性を持つ 既存アイテムがすべてそこへバックフィルされる。

バックフィルについては、3 つの点が見落とされやすい:

  • 完了するまでインデックスをクエリできない。 インデックスは CREATING を報告し (コピーが始まると Backfilling フラグが立つ)、ステータスが ACTIVE になるまで そのインデックスへの Query は拒否される。
  • バックフィルの読み取りは無料だが、インデックスへの書き込みは実費だ。 DynamoDB は 既存アイテムを内部キャパシティで読むので、その走査はテーブルに課金されない — だが 各アイテムはインデックス自身の書き込みキャパシティを通ってインデックスに入る。 プロビジョニング不足の GSI はバックフィルを這うような速度に変える。オンデマンドの テーブルならキャパシティは自動で合わせられる。
  • 所要時間はテーブルサイズに比例する。 小さなテーブルなら数分、数百ギガバイトを 抱えるテーブルなら数時間。DescribeTable が報告するのはフェーズであって、 進捗率ではない。

よくある質問

既存の DynamoDB テーブルに GSI を追加できるか? できる。GSI は UpdateTable でいつでも稼働中のテーブルに追加でき、1 回の呼び出しに つきインデックスは 1 つ、DynamoDB がインデックスをバックフィルするあいだもテーブルは 読み書きを受け付け続ける。テーブル作成時に固定されるのは LSI だけだ。

GSI のバックフィルにはどれくらいかかるか? テーブルサイズとインデックスの書き込みキャパシティ次第だ — 小さなテーブルなら数分、 大きなテーブルなら数時間。バックフィルが終わるまでインデックスは CREATING を報告し、 ステータスが ACTIVE になるまでそのインデックスへのクエリは拒否される。

作成したあとに GSI を変更できるか? できない。既存の GSI のキーや射影を変える手段は DynamoDB にない — 望む形の代わりの インデックスを作り、読み取り側をそちらへ移し、古いほうを削除する。例外は プロビジョンドスループットで、これはその場で更新できる。

既存のテーブルに LSI を追加できるか? できない。LSI は CreateTable で宣言した場合にのみ存在し、あとからどんなツールでも 追加できない。既存のテーブルで第 2 ソート順が必要なら、答えは同じパーティションキーを 持つ GSI だ。

DynoTable を開く

DynoTable のテーブル設定ダイアログはテーブルのキー構造と、キー付きのすべての GSI と LSI を 一覧するので、自分で DescribeTable を走らせずに、テーブルがすでにどのアクセス パターンを満たすかが見える。

注文テーブルのキー構造とその GSI を示す DynoTable のテーブル設定ダイアログ。
注文テーブルのキー構造とその GSI を示す DynoTable のテーブル設定ダイアログ。

ビジュアルなフィルタービルダーにはインデックスピッカーがあり、条件を足すにつれて QueryScan を導出するので、フル Scan への高いフォールバックが何も走らせる前に 見える。

status-placed GSI を選び、導出された Query バッジ付きのフィルタービルダーのインデックスピッカー。
status-placed GSI を選び、導出された Query バッジ付きのフィルタービルダーのインデックスピッカー。

同じダイアログから GSI の作成と削除もできる。キースキーマを指定し、ALL / KEYS_ONLY / INCLUDE の射影を選び、プロビジョンドテーブルではインデックスごとの スループットを設定し、DynamoDB がインデックスを構築するあいだ Creating/Backfilling の ライブステータスを眺める。LSI は読み取り専用で一覧される — それは DynamoDB のルール であってツールの制約ではない — また既存の GSI は置き換えられるが編集はできない。 テーブル管理は有料プランの機能で、トライアルにも含まれる。

DynoTable をダウンロードしてインデックスを直接調べてクエリし、 シングルテーブル設計プランナー でアクセス パターンの一覧を、コミット前に PK/SK/GSI レイアウトへ変えよう。