中級読了 2 分

DynamoDB のシングルテーブル設計

SQL から来ると、本能的にエンティティごとに1つのテーブル — customersordersorder_items — にしたくなります。DynamoDB では、その本能はたいてい誤りです。 オーバーロードしたキーのプレフィックスで区別しながら すべての エンティティを 1つのテーブルに格納すると、親とその子を 1回の Query で取得できます — 結合も N+1 もありません。

エンティティではなく、アクセスパターンから始める

シングルテーブル設計は アクセスパターン優先 です。単一のキーを選ぶ前に、アプリが 行うすべての読み取りを書き出してください — 「顧客のプロフィールを取得する」「顧客の 注文を新しい順に一覧する」「すべてのオープンな注文を見つける」 — キーはそのリストに 応えるためだけに存在するからです。リレーショナルの正規化はストレージを最適化し、 DynamoDB のモデリングは、すでに実行すると分かっているクエリを最適化します。それらを 列挙し、各クエリが1回の Query になるようにキーを設計してください。

考え方

汎用的なキー名(PKSK)を選び、エンティティの型を値にエンコードします。

PKSKattributes
CUSTOMER#42PROFILEname, email, plan
CUSTOMER#42ORDER#2026-001total, status
CUSTOMER#42ORDER#2026-002total, status

これで1回の Query PK = "CUSTOMER#42" が、プロフィール すべての注文を、1回の 課金される読み取りで返します。SK begins_with "ORDER#" で注文だけに絞り込めます。

視覚的には、オーバーロードしたアイテムは1つのパーティションキーの下に、単一のアイテムコレクションとして積み重なります。

Partition: CUSTOMER#42SK: PROFILESK: ORDER#2026-001SK: ORDER#2026-002One Query

パーティションを1回読むだけで、顧客とすべての注文がまとめて返ってきます。

オーバーロードした GSI

同じ手法はインデックスでも使えます。アイテムに汎用的な GSI1PK/GSI1SK を付け、 各アイテムがそれらの属性に何を書き込むかに応じて、1つの GSI が複数のアクセス パターンに応えます。

PKSKGSI1PKGSI1SK
ORDER#001METADATASTATUS#OPEN2026-01-04
ORDER#002METADATASTATUS#OPEN2026-01-05

これで Query GSI1 WHERE GSI1PK = "STATUS#OPEN" がオープンな注文を日付順に一覧します — ベーステーブルでは答えられないパターンです。別のエンティティは、独自の意味で GSI1 を再利用できます(例: CATEGORY#books)。1つのインデックスで、多くのクエリ。

多対多: 隣接リスト

リレーションシップ(多くのチームに属するユーザー、多くのユーザーを持つチーム)には、 id を入れ替えてエッジを 2回 書き込みます: PK=USER#1, SK=TEAM#9PK=TEAM#9, SK=USER#1。どちらの側をクエリしても他方を一覧できます — 結合テーブルの DynamoDB 版です。

シングルテーブルにしないとき

それはタダではありません。1つのオーバーロードしたテーブルは、理解しにくく、進化させ にくく、分析に不向きです。アクセスパターンが本当に未知だったり常に変化したりする、 あるいはデータがほとんど分析用なら、テーブルを分ける(または別のストアを使う)方が 理にかなうこともあります。シングルテーブルが勝つのは、パターンが 既知で大量 の ときです。

形を誤ったときのコスト

別々のテーブルとしてモデル化すると、顧客を再構成するために Scan やクライアント側の 結合を強いられます。それが Scan の落とし穴 です。まず アクセスパターンをモデル化し、それから各パターンを Query にするキーを設計して ください。

これらのアイテムが読み取りごとにいくらかかるかを アイテムサイズ & キャパシティ計算ツール で 見積もり、DynoTable を試して シングルテーブルのスキーマを閲覧し、 オーバーロードしたコレクションを並べて確認してください。

更新日