DynamoDB でリレーショナルデータをモデル化する例 - Amazon DynamoDB

DynamoDB でリレーショナルデータをモデル化する例

この例では、Amazon DynamoDB でリレーショナルデータをモデル化する方法について説明します。DynamoDB テーブルの設計は、「リレーショナルモデル化」に示されているリレーショナルオーダーのエントリスキーマに対応しています。この設計では、単一の隣接リストではなく複数の特殊なテーブルを使用し、戦略的 GSI を活用してすべてのアクセスパターンを効率的に処理しながら、明確な運用上の境界を提供します。

設計アプローチでは、集約指向の原則を使用し、厳格なエンティティ境界ではなくアクセスパターンに基づいてデータをグループ化します。主な設計上の決定事項には、アクセス相関が低いエンティティに個別のテーブルを使用すること、常に一緒にアクセスされる場合に関連データを埋め込むこと、関係を特定するための項目コレクションを使用することが含まれます。

次のテーブルとそれに付随するインデックスは、リレーショナルオーダーのエントリスキーマをサポートしています。

従業員テーブルの設計

従業員テーブルには、従業員情報が項目ごとに 1 つのエンティティとして保存され、従業員を直接検索できるように最適化し、戦略的 GSI を通じて複数のクエリパターンがサポートされます。このテーブルは、独立した運用特性を持ち、エンティティ間のアクセス相関が低いエンティティに対して個別のテーブルを設計する原則を示しています。

このテーブルでは、各従業員が個別のエンティティであるため、ソートキーなしでシンプルなパーティションキー (employee_id) を使用します。4 つの GSI により、さまざまな属性による効率的なクエリが可能になります。

  • EmployeeByName GSI - すべての従業員属性で INCLUDE 射影を使用して、従業員の詳細を名前で完全に取得し、employee_id をソートキーとして重複する可能性のある名前を処理します。

  • EmployeeByWarehouse GSI - 必須属性 (名前、job_title、hire_date) のみを含む INCLUDE 射影を使用して、倉庫ベースのクエリをサポートしながらストレージコストを最小限に抑えます

  • EmployeeByJobTitle GSI - レポートと組織分析のための INCLUDE 射影を使用してロールベースのクエリを有効にします

  • EmployeeByHireDate GSI - hire_date をソートキーとする静的パーティションキー値「EMPLOYEE」を使用して、最近の採用者に対して効率的な日付範囲クエリを有効にします。従業員の追加/更新は通常 1,000 WCU 未満であるため、ホットパーティションの問題が発生することなく、単一のパーティションで書き込み負荷を処理できます。

従業員テーブル - ベーステーブル構造
employee_id (PK) 名前 phone_number Warehouse_id job_title hire_date entity_type
emp_001 John Smith ["+1-555-0101"] wh_sea マネージャー 2024-03-15 EMPLOYEES
emp_002 Jane Doe ["+1-555-0102", "+1-555-0103"] wh_sea アソシエイト 2025-01-10 EMPLOYEES
emp_003 Bob Wilson ["+1-555-0104"] wh_pdx アソシエイト 2025-06-20 EMPLOYEES
emp_004 Alice Brown ["+1-555-0105"] wh_pdx スーパーバイザー 2023-11-05 EMPLOYEES
emp_005 Charlie Davis ["+1-555-0106"] wh_sea アソシエイト 2025-12-01 EMPLOYEES
EmployeeByName GSI - 従業員名クエリのサポート
名前 (GSI-PK) employee_id (GSI-SK) phone_number Warehouse_id job_title hire_date
Alice Brown emp_004 ["+1-555-0105"] wh_pdx スーパーバイザー 2023-11-05
Bob Wilson emp_003 ["+1-555-0104"] wh_pdx アソシエイト 2025-06-20
Charlie Davis emp_005 ["+1-555-0106"] wh_sea アソシエイト 2025-12-01
Jane Doe emp_002 ["+1-555-0102", "+1-555-0103"] wh_sea アソシエイト 2025-01-10
John Smith emp_001 ["+1-555-0101"] wh_sea マネージャー 2024-03-15
EmployeeByWarehouse GSI - 倉庫クエリのサポート
Warehouse_id (GSI-PK) employee_id (GSI-SK) 名前 job_title hire_date
wh_pdx emp_003 Bob Wilson アソシエイト 2025-06-20
wh_pdx emp_004 Alice Brown スーパーバイザー 2023-11-05
wh_sea emp_001 John Smith マネージャー 2024-03-15
wh_sea emp_002 Jane Doe アソシエイト 2025-01-10
wh_sea emp_005 Charlie Davis アソシエイト 2025-12-01
EmployeeByJobTitle GSI - 役職クエリのサポート
job_title (GSI-PK) employee_id (GSI-SK) 名前 Warehouse_id hire_date
アソシエイト emp_002 Jane Doe wh_sea 2025-01-10
アソシエイト emp_003 Bob Wilson wh_pdx 2025-06-20
アソシエイト emp_005 Charlie Davis wh_sea 2025-12-01
マネージャー emp_001 John Smith wh_sea 2024-03-15
スーパーバイザー emp_004 Alice Brown wh_pdx 2023-11-05
EmployeeByHireDate GSI - 最近の採用者クエリのサポート
entity_type (GSI-PK) hire_date (GSI-SK) employee_id 名前 Warehouse_id
EMPLOYEES 2023-11-05 emp_004 Alice Brown wh_pdx
EMPLOYEES 2024-03-15 emp_001 John Smith wh_sea
EMPLOYEES 2025-01-10 emp_002 Jane Doe wh_sea
EMPLOYEES 2025-06-20 emp_003 Bob Wilson wh_pdx
EMPLOYEES 2025-12-01 emp_005 Charlie Davis wh_sea

顧客テーブルの設計

顧客テーブルは、Account_rep_id を戦略的に非正規化して顧客情報を維持し、アカウント担当者のクエリを効率的に実行できるようにします。この設計の選択により、わずかなストレージオーバーヘッドと引き換えにクエリパフォーマンスが向上し、顧客データとアカウント担当者データの結合が不要になります。

このテーブルは、リスト属性を使用して顧客ごとに複数の電話番号をサポートしており、DynamoDB のスキーマの柔軟性を示しています。単一の GSI により、アカウント担当者のワークフローが有効になります。

  • CustomerByAccountRep GSI - 名前と E メール属性を含む INCLUDE 射影を使用して、完全な顧客レコードの取得を必要とせずに、アカウント担当者の顧客管理をサポートします。

顧客テーブル - ベーステーブル構造
customer_id (PK) 名前 phone_number E メール account_rep_id
cust_001 Acme Corp ["+1-555-1001"] contact@acme.com rep_001
cust_002 TechStart Inc ["+1-555-1002", "+1-555-1003"] info@techstart.com rep_001
cust_003 Global Traders ["+1-555-1004"] sales@globaltraders.com rep_002
cust_004 BuildRight LLC ["+1-555-1005"] orders@buildright.com rep_002
cust_005 FastShip Co ["+1-555-1006"] support@fastship.com rep_003
CustomerByAccountRep GSI - アカウント担当者クエリのサポート
account_rep_id (GSI-PK) customer_id (GSI-SK) 名前 E メール
rep_001 cust_001 Acme Corp contact@acme.com
rep_001 cust_002 TechStart Inc info@techstart.com
rep_002 cust_003 Global Traders sales@globaltraders.com
rep_002 cust_004 BuildRight LLC orders@buildright.com
rep_003 cust_005 FastShip Co support@fastship.com

注文テーブルの設計

注文テーブルは、注文ヘッダーと注文項目に個別の項目を含む垂直パーティショニングを使用します。この設計により、すべての注文コンポーネントを同じパーティション内に維持しながら、効率的な製品ベースのクエリが可能になり、効率的にアクセスできるようになります。各注文は複数の項目で構成されます。

  • 注文ヘッダー - PK=order_id、SK=order_id の注文メタデータが含まれます

  • 注文項目 - PK=order_id、SK=product_id を持つ個々の明細項目。直接の製品クエリを有効にします

注記

この垂直パーティショニングアプローチは、埋め込み注文項目のシンプルさと引き換えに、クエリの柔軟性を高めます。各注文項目は個別の DynamoDB 項目になり、すべての注文データを同じパーティション内に維持しながら効率的な製品ベースのクエリを実行し、単一のリクエストで効率的に取得できるようになります。

このテーブルには、顧客検索を必要とせずに直接アカウント担当者クエリを有効にするための account_rep_id (顧客テーブルから複製) の戦略的な非正規化が含まれています。高スループットの書き込みシナリオの場合、OPEN の注文には、複数のパーティションにわたる書き込みシャーディングを有効にするためのステータスとシャード属性が含まれます。

4 つの GSI は、最適化された射影を使用してさまざまなクエリパターンをサポートします。

  • OrderByCustomerDate GSI - 注文の概要と項目の詳細を含む INCLUDE 射影を使用して、日付範囲フィルタリングによる顧客の注文履歴をサポートします

  • OpenOrdersByDate GSI (スパース、シャード) - 5 つのシャードを持つマルチ属性パーティションキー (ステータス + シャード) を使用して、5,000 WPS (1 秒あたりの書き込み) をパーティション全体に分散します (各パーティションに 1,000 WPS、DynamoDB の パーティション制限 1,000 WCU に一致)。OPEN の注文のみをインデックスします (全体の 20%)。これにより、GSI ストレージコストを削減できます。クライアント側で結果をマージし、5 つのシャードすべてにわたって並列クエリを実行する必要があります

  • OrderByAccountRep GSI - 完全な注文詳細がないアカウント担当者のワークフローをサポートするために、注文概要属性を含む INCLUDE 射影を使用します

  • ProductInOrders GSI - OrderItem レコード (PK=order_id、SK=product_id) から作成されたこの GSI により、特定の製品を含むすべての注文を検索するクエリが可能になります。製品需要分析のために、注文コンテキスト (customer_id、order_date、数量) を含む INCLUDE 射影を使用します

注文テーブル - ベーステーブル構造 (垂直パーティショニング)
PK SK customer_id order_date ステータス account_rep_id quantity 料金 シャード
ord_001 ord_001 cust_001 2025-11-15 クローズ rep_001
ord_001 prod_100 5 25.00
ord_002 ord_002 cust_001 2025-12-20 OPEN rep_001 0
ord_002 prod_101 10 15.00
ord_003 ord_003 cust_002 2026-01-05 OPEN rep_001 2
ord_003 prod_100 3 25.00
OrderByCustomerDate GSI - 顧客注文クエリのサポート
customer_id (GSI-PK) order_date (GSI-SK) order_id ステータス total_amount order_items シャード
cust_001 2025-11-15 ord_001 クローズ 225.00 [{product_id: "prod_100", qty: 5}]
cust_001 2025-12-20 ord_002 OPEN 150.00 [{product_id: "prod_101", qty: 10}] 0
cust_002 2026-01-05 ord_003 OPEN 175.00 [{product_id: "prod_100", qty: 3}] 2
cust_003 2025-10-10 ord_004 クローズ 250.00 [{product_id: "prod_101", qty: 5}]
cust_004 2026-01-03 ord_005 OPEN 200.00 [{product_id: "prod_100", qty: 20}] 1
OpenOrdersByDate GSI (スパース、シャード) - 高スループットの Open 注文クエリのサポート
ステータス (GSI-PK-1) シャード (GSI-PK-2) order_date (SK) order_id customer_id account_rep_id order_items total_amount
OPEN 0 2025-12-20 ord_002 cust_001 rep_001 [{product_id: "prod_101", qty: 10}] 150.00
OPEN 1 2026-01-03 ord_005 cust_004 rep_002 [{product_id: "prod_100", qty: 20}] 200.00
OPEN 2 2026-01-05 ord_003 cust_002 rep_001 [{product_id: "prod_100", qty: 3}] 175.00
OrderByAccountRep GSI - アカウント担当者の注文クエリのサポート
account_rep_id (GSI-PK) order_date (GSI-SK) order_id customer_id ステータス total_amount
rep_001 2025-11-15 ord_001 cust_001 クローズ 225.00
rep_001 2025-12-20 ord_002 cust_001 OPEN 150.00
rep_001 2026-01-05 ord_003 cust_002 OPEN 175.00
rep_002 2025-10-10 ord_004 cust_003 クローズ 250.00
rep_002 2026-01-03 ord_005 cust_004 OPEN 200.00
ProductInOrders GSI - 製品注文クエリのサポート
product_id (GSI-PK) order_id (GSI-SK) customer_id order_date quantity
prod_100 ord_001 cust_001 2025-11-15 5
prod_100 ord_003 cust_002 2026-01-05 3
prod_101 ord_002 cust_001 2025-12-20 10

製品テーブルの設計

製品テーブルは、項目コレクションパターンを使用して、製品メタデータと在庫データの両方を同じパーティション内に保存します。この設計では、製品と在庫間の識別関係を活用します。親製品がないと在庫は存在できません。製品メタデータに SK=product_id を、在庫項目に SK=warehouse_id を使用し、PK=product_id を設定すると、個別の在庫テーブルと GSI が不要になり、コストが約 50% 削減されます。

このパターンにより、個々の倉庫在庫 (複合キーを持つ GetItem) と製品のすべての倉庫在庫 (パーティションキーに対するクエリ) の両方に対する効率的なクエリが可能になります。製品メタデータ項目の total_inventory 属性は、合計在庫数をすばやく検索するための非正規化集計を提供します。

製品テーブル - ベーステーブル構造 (項目コレクションパターン)
product_id (PK) Warehouse_id (SK) product_name category unit_price inventory_quantity total_inventory
prod_100 prod_100 ウィジェット A ハードウェア 25.00 500
prod_100 wh_sea 200
prod_100 wh_pdx 150
prod_100 wh_atl 150
prod_101 prod_101 ガジェット B 電子機器 50.00 300
prod_101 wh_sea 100
prod_101 wh_pdx 200

各テーブルは、必要なアクセスパターンを効率的にサポートするように、特定のグローバルセカンダリインデックス (GSI) で設計されています。この設計では、戦略的な非正規化とスパースインデックス作成を備えた集約指向の原則を使用して、パフォーマンスとコストの両方を最適化します。

主要な設計の最適化には以下が含まれます。

  • スパース GSI - OpenOrdersByDate は OPEN の注文 (全体の 20%) のみをインデックス化するため、GSI ストレージコストを削減できます。

  • 項目コレクションパターン - 製品テーブルは PK=product_id、SK=warehouse_id を使用して在庫を保存し、個別の在庫テーブルを排除します。

  • Order + OrderItems 集約 - アクセス相関が 100% であるため、単一の項目として埋め込まれます

  • 戦略的な非正規化 - 効率的なクエリのために注文テーブルで account_rep_id を重複させる

最後に、前に定義したアクセスパターンを再度使用することができます。次のテーブルは、戦略的 GSIs を備えたマルチテーブル設計を使用して、各アクセスパターンを効率的にサポートする方法を示しています。各パターンは、直接キー検索または単一の GSI クエリのいずれかを使用するため、コストのかかるスキャンを回避し、あらゆる規模で一貫したパフォーマンスを提供します。

S 番号 アクセスパターン クエリの状態

1

従業員 ID で従業員の詳細を検索する

従業員テーブル: GetItem(employee_id="emp_001")

2

従業員名で従業員の詳細をクエリする

EmployeeByName GSI: Query(name="John Smith")

3

従業員の電話番号を検索する (複数可)

従業員テーブル: GetItem(employee_id="emp_001")

4

顧客の電話番号を検索する (複数可)

顧客テーブル: GetItem(customer_id="cust_001")

5

日付範囲内の顧客の注文を取得する

OrderByCustomerDate GSI: Query(customer_id="cust_001", order_date BETWEEN "2025-01-01" AND "2025-12-31")

6

日付範囲内のすべての OPEN の注文を表示する

OpenOrdersByDate GSI: マルチ属性 PK (status="OPEN + shard=0-4) を使用して 5 つのシャードを並列にクエリし、SK=order_date BETWEEN "2025-01-01" AND "2025-12-31"、結果をマージします

7

最近雇用したすべての従業員を確認する

EmployeeByHireDate GSI: Query(entity_type="EMPLOYEE", hire_date >= "2025-01-01")

8

倉庫のすべての従業員を検索する

EmployeeByWarehouse GSI: Query(warehouse_id="wh_sea")

9

製品の注文中のすべての項目を取得する

ProductInOrders GSI: Query(product_id="prod_100")

10

すべての倉庫の製品在庫を取得する

製品テーブル: Query(product_id="prod_100")

11

アカウント担当者別に顧客を取得する

CustomerByAccountRep GSI: Query(account_rep_id="rep_001")

12

アカウント担当者別に注文を取得する

OrderByAccountRep GSI: Query(account_rep_id="rep_001")

13

役職を持つ従業員を取得する

EmployeeByJobTitle GSI: Query(job_title="Manager")

14

商品および倉庫別に在庫を取得する

製品テーブル: GetItem(product_id="prod_100", warehouse_id="wh_sea")

15

商品在庫総数を取得する

製品テーブル: GetItem(product_id="prod_100", warehouse_id="prod_100")