DynamoDB のインデックスプロジェクション:KEYS_ONLY、INCLUDE、ALL
セカンダリインデックスを作成しても、DynamoDB はアイテム全体を自動的にそこへコピーする わけではありません。あなたが 何を コピーするかを選びます — インデックスの プロジェクション です。少なすぎれば、クエリは残りを取りに行く 2 回目の読み取りを払うことになり、すべてを 入れれば、更新のたびに余分なストレージと書き込みコストを払います。インデックス作成時に 一度設定し、それと付き合っていくトレードオフです。
(これを プロジェクション式 と混同しないでください。プロジェクション式は 1 回の読み取りが 返す 属性を絞り込むものです。このページは インデックスが物理的に保存するもの に ついてです — もう一方については プロジェクション式 を参照してください。)
DynamoDB のインデックスプロジェクションとは?
プロジェクションとは、DynamoDB がベーステーブルからセカンダリインデックスへコピーする属性の集合です。3 つのタイプから 1 つを選びます:KEYS_ONLY(キーだけ)、INCLUDE(キーに加えて、名前を指定した属性のリスト)、ALL(アイテム全体)。プロジェクションを増やすほどベーステーブルからの取得は減りますが、ストレージと書き込みのコストは高くなります。
- プロジェクションとは、セカンダリインデックスに コピーされる 属性の集合です。
KEYS_ONLY— テーブルとインデックスのキーのみ。最小・最安。INCLUDE— キーに加えて、あなたが選ぶ追加属性の名前付きリスト。ALL— アイテムのすべての属性。最大。クエリはベーステーブルを一切必要としません。- プロジェクションされていない属性を読むと、GSI ではベーステーブルからの取得が強制される — 目に見えない余分なコストです。(LSI は できます、プロジェクションされていない属性を 追加の読み取りコストで取得することが。)
- プロジェクションが多い = ストレージ増 + 書き込みコスト増 — すべてのベーステーブル 書き込みがインデックスに伝播するためです。
問題:2 回読まされるインデックス
未対応 のチケットを優先度で一覧する GSI を持つサポートデスクを運用しているとします。
スリムに保つため KEYS_ONLY をプロジェクションします。クエリは速く返ります — しかし
返ってくるのはチケット ID だけで、キュー画面には各チケットの件名、担当者、経過時間が
必要です。
そこでコードは、すべての結果を肉付けするためにベーステーブルに対して 2 回目の読み取りを 行います。設計した「1 回のクエリ」は、実際にはクエリ プラス N 回の get であり、節約 しようとしていたレイテンシとコストがそのまま戻ってきます。プロジェクションがアクセス パターンに対して薄すぎたのです。
各プロジェクションタイプが何をコピーするか
KEYS_ONLYはベーステーブルのキー と インデックスのキーだけを保存します。クエリが どの アイテムが一致するかだけを知る必要があり、詳細は別の場所で取得する — あるいは まったく取得しない — 場合に使います。INCLUDEはキーに加えて、あなたが名前を挙げた固定の属性リストを保存します。これが スイートスポット:クエリのレンダリングに必要なフィールドをちょうどプロジェクションし、 それ以上はしません。ALLはアイテム全体をコピーします。クエリはインデックスだけで完全に自己完結します。 代償として、アイテム全体のストレージと書き込みスループットをそこへ複製します。
サポートデスクのキューには、subject、assignee、age を持つ INCLUDE が正解です —
キューはインデックスだけからレンダリングされ、2 回目の取得もなく、チケットの大きな body
をインデックスに複製することもありません。
あなたがトレードしているコスト
プロジェクションするすべての属性は
二重に保存され、
ベースアイテムが変わるたびにインデックス内で書き直されます。そのため、頻繁に更新される
テーブルへの気前のよい ALL プロジェクションは、ストレージと書き込みキャパシティの両方を
何倍にもします。規律はこうです:クエリが 読む ものをプロジェクションする、「念のため
すべて」ではなく。
知っておく価値のある微妙な点:スパース インデックスでは、プロジェクションはやはり
インデックスキーを持つアイテムだけを保持します — そのため
スパースインデックス への INCLUDE/ALL は、インデックス
自体が小さいので小さいままです。プロジェクションのストレージと書き込みの乗数を
DynamoDB 料金計算ツール で見積もり、インデックスの
クエリそのものは
DynamoDB Expression Builder で組み立てましょう。
DynoTable でプロジェクションを見る
DynoTable はテーブルのセカンダリインデックスを一つずつ一覧表示し、その一つを通して 直接クエリできるようにします。同じアクセスパターンをベーステーブルと GSI に対して実行し、 結果を比べてみましょう — インデックスの結果に欠けている属性は、まさにそれがプロジェクション していないものなので、プロジェクションの効果がテーブル定義を読み直さずに目で見えます。

落とし穴と次のステップ
- GSI でプロジェクションされていない属性はベーステーブルからの取得を意味する — プロジェクションはクエリがレンダリングするものを軸に設計しましょう。
ALLがタダなことはめったにない — ストレージと書き込みコストを複製します。 インデックスが本当にすべてのフィールドを必要とするのでない限り、INCLUDEを デフォルトに。- プロジェクションはほぼ固定。 GSI のプロジェクションを後から自由に編集することは インデックスを作り直さずにはできません — 最初に慎重に選びましょう。
- 関連: GSI と LSI と スパースインデックス は、プロジェクションが実際に どれだけ保存するかを形づくります。
再設計の前に、各インデックスが実際に何を返すのか見たいですか? DynoTable をダウンロード してテーブルを直接クエリしましょう。


