PR

【データ永続化】DynamoDBシングルテーブル設計:マルチテナントSaaSのデータ分離とコスト最適化を両立する実践テクニック

はじめに:RDBの常識を捨てよ。DynamoDBシングルテーブル設計という革命

リレーショナルデータベース(RDB)に慣れ親しんだエンジニアが、Amazon DynamoDBを初めて使うとき、必ずと言っていいほど同じ過ちを犯します。それは、エンティティごとにテーブルを細かく正規化して作成してしまうことです。

Usersテーブル、Productsテーブル、Ordersテーブル…。一見すると美しく整理されているこの設計は、DynamoDBの世界では、コスト、パフォーマンス、スケーラビリティのすべてを悪化させるアンチパターンとなり得ます。

SaaSアプリケーション、特にマルチテナント環境のデータ永続化において、DynamoDBの真の力を引き出す設計思想、それが「シングルテーブル設計」です。これは、アプリケーションのすべてのエンティティを、たった一つのテーブルに格納する、RDBの常識とは真逆のアプローチです。

この記事を読めば、あなたもシングルテーブル設計の核心を理解し、テナントデータの完全な分離究極のコスト最適化を両立させる、スケーラブルなデータ基盤を構築できるようになります。

シングルテーブル設計の核心:アクセスパターンに基づいたキー設計

シングルテーブル設計の成否は、すべてプライマリキーの設計にかかっています。RDBのように後から柔軟なクエリを発行するのではなく、まずアプリケーションが必要とする「全アクセスパターン」を事前に洗い出し、そのすべてに効率的に応答できるキー構造を設計します。

  • パーティションキー(PK): テナント分離の要です。マルチテナントSaaSでは、PKに必ずテナントIDを含めるのが鉄則です。一般的にはTENANT#<tenant_id>のようなプレフィックスを付けた文字列を使います。これにより、あるテナントに関連する全てのデータが、物理的に近い場所に格納され、効率的に取得できます。

  • ソートキー(SK): 1対多の複雑な関係を表現する魔法のキーです。同じテナント(同じPK)の中で、異なる種類のデータ(ユーザー、注文、商品など)を区別し、並べ替えるために使います。USER#<user_id>ORDER#<order_id>#ITEM#<item_id>のように、エンティティの種類とIDを#で連結して階層構造を持たせるのが一般的なテクニックです。

【実践例】SaaSアプリケーションのデータモデリング

言葉だけでは分かりにくいので、具体的な例を見ていきましょう。テナントAに所属するユーザーX注文1注文2を行った場合のテーブル構造です。

PK (Partition Key) SK (Sort Key) データ
TENANT#A USER#X { "name": "Haru", "email": "..." }
TENANT#A ORDER#1 { "date": "2025-08-05", "amount": 5000 }
TENANT#A ORDER#2 { "date": "2025-08-06", "amount": 3000 }

この設計により、以下のような複雑なデータ取得が、たった1回のQuery APIコールで、極めて高速に実行できます。

  • 特定テナントの全データを取得: PK = TENANT#A を指定してクエリ。
  • 特定テナントの全注文を取得: PK = TENANT#A かつ SKが "ORDER#" で始まる という条件でクエリ。
  • 特定ユーザーのプロフィールと全注文を同時に取得: PK = TENANT#A かつ SKが "USER#X" または "ORDER#" で始まる という条件でクエリ。(※実際にはより工夫が必要ですが、概念として)

このように、関連するデータをまとめて取得できるため、RDBで頻発するN+1問題のようなパフォーマンスのボトルネックを根本的に解決できます。

GSI(グローバルセカンダリインデックス)の戦略的活用

プライマリキーだけでは対応できないアクセスパターンも存在します。例えば、「メールアドレスからユーザーを検索したい」といったケースです。このような逆引き検索は、GSI (Global Secondary Index) を作成することで実現します。

ただし、GSIの設計でもテナント分離の原則は変わりません。GSIのパーティションキーにもテナントIDを含めるか、あるいはアプリケーションロジックでテナントIDによる絞り込みを徹底する必要があります。

鉄壁のテナント分離:IAMポリシーによる最終防衛ライン

シングルテーブル設計では、全テナントのデータが同じテーブルに存在するため、セキュリティが懸念されるかもしれません。しかし、IAMポリシーを組み合わせることで、RDB以上に堅牢なデータ分離を実現できます。

アプリケーションの実行ロールにアタッチするIAMポリシーで、DynamoDBのdynamodb:LeadingKeys条件キーを使用します。これにより、「認証されたユーザーは、自身のテナントID(JWTから取得)で始まるパーティションキーを持つアイテムしか読み書きできない」というルールをデータベースレベルで強制できます。

{
    "Effect": "Allow",
    "Action": "dynamodb:Query",
    "Resource": "arn:aws:dynamodb:*:*:table/YourSaaSTable",
    "Condition": {
        "ForAllValues:StringEquals": {
            "dynamodb:LeadingKeys": [
                "TENANT#${cognito:amr[2]}"
            ]
        }
    }
}

この設定により、たとえアプリケーションのコードにバグがあり、他のテナントIDを指定してクエリを発行しようとしても、IAMレベルで確実にブロックされます。これこそが、シングルテーブル設計における究極のセキュリティモデルです。

まとめ:シングルテーブル設計は、SaaSの成長を支えるスケーラブルなデータ基盤である

DynamoDBのシングルテーブル設計は、間違いなく初期の学習コストが高いアプローチです。しかし、一度その設計思想をマスターすれば、その見返りは計り知れません。

  • 圧倒的なパフォーマンス: 関連データを1回のAPIコールで取得。
  • 究極のコスト効率: プロビジョニングしたキャパシティを全テナントで共有し、無駄を排除。
  • 無限のスケーラビリティ: DynamoDBの水平スケーリング能力を最大限に活用。
  • 堅牢なセキュリティ: IAMポリシーとの組み合わせによる鉄壁のテナント分離。

これらは、SaaSビジネスを成功に導く上で不可欠な要素です。RDBの常識を一度リセットし、シングルテーブル設計という新しいパラダイムを受け入れること。それが、あなたのSaaSの成長を支える、最も合理的でスケーラブルなデータ基盤を築くための第一歩です。

コメント

タイトルとURLをコピーしました