マルチテナント環境向けに堅牢なデータベーススキーマを設計するには、シングルテナントアーキテクチャと比べて根本的な考え方の転換が必要です。複数の顧客、すなわちテナントが同じ基盤インフラを共有する状況では、エンティティ関係図(ERD)がデータ分離、セキュリティ、パフォーマンスのための設計図となります。🏗️ 不適切に構築されたERDは、データ漏洩、パフォーマンスの低下、複雑な移行経路を引き起こす可能性があります。このガイドでは、特定のソフトウェアツールに依存せずに、マルチテナントシステムのモデリングにおける構造的な複雑さを解説し、アーキテクチャの原則に焦点を当てます。

共有データの核心的な課題を理解する 🏢
従来のシングルテナント構成では、各顧客が独自の隔離されたデータベースを持ちます。アプリケーションとデータの関係は1対1です。しかし、マルチテナントシステムでは、関係は1対多になります。アプリケーションは共有リソースプールから複数のテナントをサービス提供します。ERDは、すべてのクエリやトランザクションにテナントのコンテキストを明示的にエンコードしなければなりません。
主な目的は、Tenant AがTenant Bのデータをまったく見ることのないよう保証することです。たとえ同じテーブルをクエリしても同様です。これはしばしば論理的分離と呼ばれます。ERDは、アプリケーションロジックにのみ依存するのではなく、スキーマ設計を通じてこの分離をネイティブにサポートしなければなりません。🔒
分離モデルとそのスキーマ設計への影響 🏗️
テナントデータを分離するための主なモデルは3つあります。それぞれのモデルは、エンティティ関係図(ERD)へのアプローチを著しく異なったものにします。設計段階の初期に誤ったモデルを選択すると、後で高コストな再設計を強いられる可能性があります。
1. テナントごとのデータベース(物理的分離)
このモデルでは、各テナントに独自の物理的データベースインスタンスが割り当てられます。ERDはシングルテナント設計と同一のままです。すべてのテーブルは、それぞれ独自のデータベースコンテナ内で独立して存在します。
- 利点:最大のセキュリティと分離性。テナント間でのデータ漏洩は物理的に不可能です。
- 欠点:運用コストが高くなる。数百または数千のデータベースを管理するのは複雑です。
- スキーマへの影響:ERDはテナント識別子カラムを考慮する必要がない。なぜなら、データベース自体が識別子として機能するからである。
2. テナントごとのスキーマ(論理的分離)
複数のテナントが1つのデータベースを共有するが、各テナントはそのデータベース内に独自のスキーマ(名前空間)を持つ。ERDはシングルテナント版とほぼ同じだが、スキーマ名はテナントに応じて変化する。
- 利点:共有テーブルよりも優れた分離性。個別のデータベースよりも管理が容易。
- 欠点:クエリの複雑さが増す。アプリケーションがスキーマを動的に切り替える必要があるため。
- スキーマへの影響:ERDはすべてのテーブルにテナントIDカラムを必要としない。代わりに、データベース接続コンテキストが分離を処理する。
3. 共有スキーマ、共有テーブル(論理的分離)
これはSaaSアプリケーションで最も一般的なモデルです。すべてのテナントがまったく同じテーブルを共有します。ERDは、すべての関連する行に各テナントの固有識別子を含めるように変更しなければなりません。
- 利点:コストと運用負荷が最低。グローバルな分析を実行しやすい。
- 欠点:ロジックに失敗した場合、データ漏洩のリスクが最も高い。テーブルが大きくなるにつれてパフォーマンスが低下する可能性がある。
- スキーマへの影響: すべてのテーブルには、必ず
tenant_id列を含める必要があります。外部キーは、整合性を保つためにこの列を参照しなければなりません。
共有スキーマのERDの設計 🔑
共有スキーマモデルを採用する際には、データの整合性とセキュリティを確保するためにERDに特定の変更が必要です。このセクションでは、図に必ず含まれるべき重要な構成要素について説明します。
テナント識別子列
ユーザー固有のデータを保持するすべてのテーブルには、そのデータの所有者を識別する列を含める必要があります。この列は通常、tenant_id または organization_id.
- データ型: 整数またはUUIDであるべきです。整数は結合処理において一般的に高速です。
- NOT NULL制約: この列は決してNULLにすべきではありません。NULL値はデータが誰にも属していないことを意味し、マルチテナント契約に違反します。
- デフォルト値: 一部のアプリケーションでは、デフォルト値がアプリケーションレベルで設定される場合がありますが、データベーススキーマはこの値の存在を強制すべきです。
外部キー関係
テーブル同士が関係する際には、関係性がテナントの境界を尊重しなければなりません。よくある誤りは、グローバルテーブル(製品カタログなど)とテナント固有のテーブル(注文など)の間に関係を設けることです。
- グローバルテーブル: 例えば
ProductsまたはCategoriesは共有される可能性があります。これらにはtenant_id. - テナントテーブル: 例えば
Ordersまたはユーザーには、tenant_id. - 結合ロジック:グローバルテーブルをテナントテーブルに結合する際、結合条件には
tenant_id一致を含める必要があります。これにより、テナント間のデータ漏洩を防ぐことができます。
隔離戦略の比較 📊
トレードオフを理解することは、適切なERD構造を選択するために不可欠です。以下の表は、主な隔離戦略の主な違いを概説しています。
| 戦略 | 隔離レベル | コスト | 管理の複雑さ | スキーマ要件 |
|---|---|---|---|---|
| テナントごとのデータベース | 物理的 | 高 | 高 | 標準(テナントIDなし) |
| テナントごとのスキーマ | 論理的 | 中 | 中 | 標準(スキーマ名) |
| 共有スキーマ | 行レベル | 低 | 低 | テナントIDカラムが必要 |
ERD設計におけるパフォーマンスの考慮点 🚀
データが蓄積されるにつれて、共有スキーマのパフォーマンスが低下する可能性があります。ERDは、テナント固有のクエリを最適化するためのインデックス戦略をサポートしなければなりません。
インデックス戦略
適切なインデックスがなければ、1つのテナントのデータを取得するクエリが、他のテナントの数百万行を含むすべての行をスキャンする可能性があります。
- 複合インデックス:以下の列から始まるインデックスを作成してください:
tenant_id。たとえば、(tenant_id,created_at) というインデックスがあると、データベースは特定のテナントのレコードを素早く検索し、並べ替えることができます。 - カバーインデックス:特定のカラムを頻繁にクエリする場合は、それらをインデックスに含めることで、テーブルの参照を回避できます。
- パーティショニング:大規模なテーブルは
tenant_idによってパーティショニングできます。これにより、ディスク上のデータが物理的に分離され、クエリ速度とバックアップ管理が向上します。
クエリ最適化
アプリケーション層は、すべてのクエリがtenant_idをWHERE句に含むことを確認しなければなりません。ERD設計はアプリケーションによるデータのフィルタリングに依存してはいけません。データベースが真実のソースでなければなりません。
- 行レベルのセキュリティ:一部のデータベースシステムは行レベルのセキュリティ(RLS)をサポートしています。ERDはこの機能を活用して、認証されたユーザーのコンテキストに基づいて行を自動的にフィルタリングできます。
- クエリプラン:クエリ実行プランを定期的に確認してください。データベースが
tenant_idインデックスを使用し、フルテーブルスキャンを行わない。
セキュリティおよびコンプライアンス上の影響 🛡️
データプライバシー規制、たとえばGDPRやCCPAは、データの保存およびアクセス方法について厳格な要件を課す。ERDはコンプライアンスにおいて重要な役割を果たす。
データの分離
コンプライアンスの要件により、データが容易に分離可能であることが求められる。テナントがデータの削除を要求した場合、システムはそのテナントに関連するすべてのレコードを特定し、削除できる必要がある。tenant_id.
- ソフトデリート:行をハード削除するのではなく、削除済みとしてマークする。これは監査の観点からより安全であることが多い。
deleted_at列は、tenant_id. - 暗号化:テナント範囲内の機密フィールドは暗号化すべきである。鍵管理戦略は、テナントの分離モデルと整合性を持たなければならない。
監査およびログ記録
監査トレースはセキュリティにとって不可欠である。テナントデータに対して行われたすべての操作はログに記録されるべきである。
- 監査テーブル:影響を受けたエンティティの
tenant_idを含む専用のテーブルを作成する。 - アクセス制御:監査ログ自体が保護されていることを確認する。管理者は、自分が管理していないテナントの監査ログを見ることはできないようにする。
スキーマの進化とマイグレーション 🔄
アプリケーションは進化する。機能が追加され、データ構造が変更される。マルチテナント環境では、すべてのテナントに変更を適用する必要があるため、スキーマのマイグレーションがより複雑になる。ダウンタイムやデータ損失を引き起こさずに済むようにする必要がある。
後方互換性
ERDを変更する際は、後方互換性が維持されていることを確認する。
- 追加的な変更:テーブルに新しい列を追加することは、nullを許容する場合、通常は安全である。
- 列の削除: これはリスクがあります。カラムを削除するには、どのテナントも使用していないことを確認し、非推奨期間を設ける必要があります。
- カラム名の変更: これによりクエリが破損する可能性があります。名前の変更よりも、新しいカラムを追加し、データを移行してから参照を切り替える方が良いです。
ダウンタイムゼロのマイグレーション
大規模なテナントの場合、マイグレーション中にテーブルをロックすることは選択肢になりません。ERDの設計はオンラインスキーマ変更をサポートしている必要があります。
- ゴーストテーブル: 構造を更新した新しいテーブルを作成し、データをコピーしてからテーブルを交換する。
- バージョン管理: 一部のシステムは、段階的な展開を可能にするために、複数のスキーマバージョンを同時にサポートしています。
避けるべき一般的な落とし穴 ⚠️
マルチテナントERDの設計には多くの要素が関与します。ここでは、システムに悪影響を及ぼす一般的なミスを紹介します。
- テナントIDを無視する: 開発中に新しく作成したテーブルに
tenant_idを追加することを忘れること。これにより、即座にデータ漏洩のリスクが生じます。 - IDのハードコード: アプリケーションコードにテナントIDをハードコードしてはいけません。実行時に動的に渡す必要があります。
- グローバルカウンター: URLやAPI応答に公開されるグローバルな自動増分カウンターは、テナント数やユーザー数を明らかにする可能性があるため、使用を避けましょう。
- 共有ファイル: ERDはデータベースに注目しますが、ファイルストレージはしばしば見過ごされます。アクセス問題を防ぐために、ファイルパスにテナント識別子を含めるようにしてください。
複雑なシナリオ向けの高度なパターン 🔍
すべてのマルチテナントシステムが同じではありません。一部のシステムは、データ構造に対するより細かい制御を必要とします。
複数組織対応
1つのテナントが複数の組織に属する場合や、その逆も考えられます。ERDは多対多関係をサポートしている必要があります。
- 結合テーブル: ユーザー、テナント、組織をリンクするために結合テーブルを使用する。
- 権限モデル: ERDは、テナントレベルでのロールベースアクセス制御(RBAC)をサポートしている必要があります。
グローバル設定 vs. テナント固有の設定
一部の構成データはグローバル(アプリ全体)ですが、他のデータはテナント固有です。
- 設定テーブル:ERDを構成して、グローバル設定とテナント固有の上書き設定を明確に区別する。
- 継承:テナント設定はグローバルデフォルトから継承する可能性があります。スキーマはこの階層を明確に反映すべきです。
ベストプラクティスの要約 ✅
セキュアでスケーラブルなマルチテナントシステムを構築するには、エンティティ関係図(ERD)が築く基盤に大きく依存します。以下の原則に従うことで、長期的な安定性を確保できます。
- 一貫性:ユーザー情報を保持するすべてのテーブルにテナント識別子が含まれていることを確認する。
- 分離:セキュリティとコスト要件に合った分離モデルを選択する。
- パフォーマンス:テナント識別子を優先するインデックスを設計する。
- セキュリティ:適切な場面では行レベルのセキュリティと暗号化を実装する。
- 保守性:サービスの中断を引き起こさないスキーマ変更を計画する。
データベーススキーマの設計は、アプリケーションのライフサイクル全体に影響を与える戦略的決定です。適切に構成されたERDは、データ漏洩を防ぎ、コンプライアンスを確保し、成長を支援します。設計段階でマルチテナントのニュアンスを慎重に検討することで、耐障害性とセキュリティに優れた基盤を築くことができます。 🏛️
アプリケーションが成長するにつれて、ERDの継続的な見直しが必要です。新しい機能はしばしば、テナント分離ルールと照らし合わせて評価しなければならない新しいデータ関係を導入します。注意を払い、設計決定を文書化し、何よりもデータの整合性を最優先してください。このアプローチにより、スケーリングする際にもアーキテクチャが堅牢なまま保たれます。











