キー設計パターン
このガイドでは、DynamoDBにおけるエンティティのパーティションキー(PK)とソートキー(SK)の設計方法を説明します。適切なキー設計は、パフォーマンス、スケーラビリティ、クエリ効率にとって重要です。
このガイドを使用するタイミング
以下が必要な場合にこのガイドを使用してください:
- 新しいエンティティタイプのキーを設計する
- 親子関係をモデル化する(Order → OrderItems)
- マルチテナントデータ分離をサポートする
- 効率的なクエリパターンを有効にする(テナント別リスト、日付フィルター)
- 楽観的ロック用のバージョニングを処理する
関連ドキュメント
- エンティティ定義パターン - これらのキーパターンを使用するエンティティの定義方法
- マルチテナントパターン - テナント分離とクロステナント操作
- バックエンド開発ガイド - 完全なモジュール実装パターン
このパターンが解決する問題
| 問題 | 解決策 |
|---|---|
| テナントの全アイテムをクエリするのが遅い | パーティションレベルの分離のためにPKにテナントコードを含める |
| すべてのキーを知らないと子アイテムをリストできない | 異なるSKプレフィックスで共有PKを使用する |
| IDが作成時間でソートできない | 一意性と時間ソートの両方を持つULIDを使用する |
| 同時更新でバージョン競合が発生する | SKのバージョンサフィックスで楽観的ロックを有効にする |
パターン選択ガイド
このデシジョンツリーを使用して、ユースケースに適したキーパターンを選択してください:
デシジョンマトリックス
| 要件 | 推奨パターン | PK構造 | SK構造 |
|---|---|---|---|
| テナント分離を伴うシンプルなCRUD | シンプルエンティティ | ENTITY#tenantCode | ulid() |
| 複数の子を持つ親 | 階層構造 | PARENT#tenantCode | TYPE#parentId[#childId] |
| 複数のエンティティバリアント | 複合SK | ENTITY#tenantCode | variant#identifier |
| クロステナント共有データ | 共通テナント | ENTITY#common | tenantCode#identifier |
| カテゴリ別設定 | マスターデータ | MASTER#tenantCode | TYPE#category#code |
| 時間ベースのクエリ | 時系列 | LOG#tenantCode#YYYY-MM | timestamp#eventId |
デシジョンツリー
開始: どのような種類のデータを保存しますか?
│
├─ スタンドアロンエンティティ(商品、顧客)
│ └─ シンプルエンティティパターンを使用
│
├─ 親子関係(注文 → 明細)
│ └─ 子は独立したアクセスが必要ですか?
│ ├─ はい → 参照付きの別PKを使用
│ └─ いいえ → 階層パターン(共有PK)を使用
│
├─ 設定/マスターデータ
│ └─ マスターデータパターンを使用
│
├─ 時間ベースのイベント(ログ、監査)
│ └─ 時系列パターンを使用
│
└─ 複数のバリアントを持つユーザー/エンティティ
└─ 複合SKパターンを使用
キー構造の概要
フレームワークは一貫したキー構造を使用します:
PK = PREFIX#TENANT_CODE
SK = IDENTIFIER[@VERSION]
ID = PK#SK (without version)
KEY_SEPARATOR定数(#)はキーコンポーネントを区切るために使用されます。
フレームワーク定数
フレームワークは@mbc-cqrs-serverless/coreで以下の定数を提供します:
| 定数 | 値 | 説明 |
|---|---|---|
KEY_SEPARATOR | # | キーコンポーネントを区切る(PKセグメント、SKセグメント、ID) |
VER_SEPARATOR | @ | ソートキーとバージョン番号を区切る |
VERSION_FIRST | 0 | 新しいエンティティの初期バージョン |
VERSION_LATEST | -1 | 最新バージョンのクエリを示す |
TENANT_COMMON | common | 共有・テナント横断データ用のテナントコード(非推奨 — DEFAULT_COMMON_TENANT_CODES を使用) |
DEFAULT_COMMON_TENANT_CODES | ['common'] | 共通テナントコードのリスト(環境変数 COMMON_TENANT_CODES で設定可能) |
DEFAULT_TENANT_CODE | single | シングルテナントモードのデフォルトテナント |
一貫したテナントコード形式
@mbc-cqrs-serverless/masterと@mbc-cqrs-serverless/tenantパッケージはSettingTypeEnum.TENANT_COMMON = 'common'(小文字)を使用しており、getUserContext()のテナントコード正規化と一貫しています。これにより、createCommonTenantSetting()やcreateCommonTenant()メソッドで保存されたデータを正しくクエリできます。
組み込みキージェネレーター
フレームワークは以下の組み込みキージェネレーターを提供します:
import { masterPk, seqPk, ttlSk } from "@mbc-cqrs-serverless/core";
// Master data partition key (マスターデータパーティションキー)
masterPk("tenant001"); // "MASTER#tenant001"
masterPk(); // "MASTER#single" (default tenant)
// Sequence partition key (シーケンスパーティションキー)
seqPk("tenant001"); // "SEQ#tenant001"
// TTL sort key for table-level TTL settings (テーブルレベルTTL設定用のTTLソートキー)
ttlSk("product"); // "TTL#product"
基本的なキー生成
コアパッケージからユーティリティをインポートします:
import {
generateId,
getTenantCode,
KEY_SEPARATOR,
VER_SEPARATOR,
removeSortKeyVersion,
addSortKeyVersion,
getSortKeyVersion,
VERSION_FIRST,
VERSION_LATEST,
TENANT_COMMON,
} from "@mbc-cqrs-serverless/core";
import { ulid } from "ulid";
キーの生成
const PRODUCT_PK_PREFIX = "PRODUCT";
// Generate PK (PKを生成)
const pk = `${PRODUCT_PK_PREFIX}${KEY_SEPARATOR}${tenantCode}`;
// 結果: "PRODUCT#tenant001"
// Generate SK (using ULID for uniqueness and sortability) (SKを生成(一意性とソート可能性のためにULIDを使用))
const sk = ulid();
// 結果: "01HX7MBJK3V9WQBZ7XNDK5ZT2M"
// Generate ID (combination of PK and SK) (IDを生成(PKとSKの組み合わせ))
const id = generateId(pk, sk);
// 結果: "PRODUCT#tenant001#01HX7MBJK3V9WQBZ7XNDK5ZT2M"
バージョン管理
// Add version to SK (SKにバージョンを追加)
const skWithVersion = addSortKeyVersion(sk, 3);
// 結果: "01HX7MBJK3V9WQBZ7XNDK5ZT2M@3"
// Remove version from SK (SKからバージョンを削除)
const baseSk = removeSortKeyVersion(skWithVersion);
// 結果: "01HX7MBJK3V9WQBZ7XNDK5ZT2M"
// Get version number from SK (SKからバージョン番号を取得)
const version = getSortKeyVersion(skWithVersion);
// 結果: 3
// Get version from SK without version suffix (バージョンサフィックスなしのSKからバージョンを取得)
const latestVersion = getSortKeyVersion(sk);
// 結果: -1 (VERSION_LATEST)
テナントコード抽出
import { getTenantCode } from "@mbc-cqrs-serverless/core";
// Extract tenant code from PK (PKからテナントコードを抽出)
const tenantCode = getTenantCode("PRODUCT#tenant001");
// 結果: "tenant001"
// Returns undefined if no separator found (セパレーターが見つからない場合はundefinedを返す)
const noTenant = getTenantCode("PRODUCT");
// 結果: undefined