SQL Server 2016のマルチスキーマ、マルチテナントデータベースを設計しています。これは、トランザクションスループットが小から中程度で、15〜20のテーブルで構成される基本的なCRUDアプリケーションにサービスを提供します。データの分離とセキュリティのために、[TenantId] [int]
と[TenantIsolationId] [uniqueidentifier]
を持つ複合主キーの使用について調査しています。これらの2つの列は、テーブル全体で階層的に繰り返され、適切な外部キーを使用して参照整合性を適用し、より深い 行レベルのセキュリティ を適用できます。
私が読んだほとんどのシナリオでは、特にスペースに関してパフォーマンスの影響があるため、GUID for [TenantIsolatonId]
の使用は物議を醸しているようです。しかし、物理ファイルのパーティション化、リソースプールの委任、レプリケーション、移植性、および一般的な参照整合性の管理。整数とGUIDの組み合わせにより、マルチテナントデータベース内での分離とセキュリティが向上します。私たちはさまざまなセキュリティ対策に拘束されているため、これにより、この複合キータイプを使用する道がさらに進みます。
子供の複合キーについて考えるとき、列の順序が指定されていることがわかっています。ただし、同じ複合キー構造をテーブルチェーンにフィードする必要がある場合、または従来の方法で分離する方がよい場合、コンセンサスに達したようには見えません。
たとえば、次の2つのテーブル構造があるとします。
CREATE TABLE [Auth].[Tenant] (
[TenantId] [int] IDENTITY(1,1) NOT NULL
,[TenantIsolationId] [uniqueidentifier] NOT NULL CONSTRAINT [DF_Tenant_TenantIsolationId] DEFAULT NEWID()
,[TenantName] [varchar](256) NOT NULL
,CONSTRAINT [PK_Tenant_TenantId_TenantIsolationId] PRIMARY KEY CLUSTERED ([TenantId] ASC, [TenantIsolationId] ASC)
,CONSTRAINT [AK_Tenant_TenantName] UNIQUE NONCLUSTERED ([TenantName] ASC)
);
CREATE TABLE [Auth].[User] (
[UserId] [int] IDENTITY(1,1) NOT NULL
,[TenantId] [int] NOT NULL
,[TenantIsolationId] [uniqueidentifier] NOT NULL
,[FirstName] [varchar](32) NOT NULL
,[LastName] [varchar](32) NOT NULL
,[UserName] [varchar](64) NOT NULL
,CONSTRAINT [PK_User_TenantId_TenantIsolationId_UserId] PRIMARY KEY CLUSTERED ([TenantId] ASC, [TenantIsolationId] ASC, [UserId] ASC)
,CONSTRAINT [AK_User_UserName] UNIQUE NONCLUSTERED ([UserName] ASC)
);
行レベルのセキュリティを実行し、[TenantId]
と[TenantIsolationId]
に基づいてデータを分離する場合、[UserId]
主キーは複合キーで上記のように処理するのが良いですか、それとも個別ですか?
例えば。:
CREATE TABLE [Auth].[User] (
[UserId] [int] IDENTITY(1,1) NOT NULL
,[TenantId] [int] NOT NULL
,[TenantIsolationId] [uniqueidentifier] NOT NULL
,[FirstName] [varchar](32) NOT NULL
,[LastName] [varchar](32) NOT NULL
,[UserName] [varchar](64) NOT NULL
,CONSTRAINT [PK_User_UserId] PRIMARY KEY CLUSTERED ([UserId] ASC)
,INDEX [IX_User_TenantId_TenantIsolationId] NONCLUSTERED ([TenantId] ASC, [TenantIsolationId] ASC)
,CONSTRAINT [FK_Tenant_TenantId_TenantIsolationId] FOREIGN KEY ([TenantId],[TenantIsolationId]) REFERENCES [Tenant]([TenantId],[TenantIsolationId])
,CONSTRAINT [AK_User_UserName] UNIQUE NONCLUSTERED ([UserName] ASC)
);
私が掘り下げたものについての私の理解に基づいて、複合キーはonlyですが、3つの列すべてのデータを常に検索する場合は、良い考えです常に。データを分離したいので、[TenantId]
にシークする前に[TenantIsolationId]
だけでなく[UserId]
も検索したくない場合は予測できません。しかし、おそらく、私は長所と短所を誤解しており、[UserId]
および[TenantId]
に対するインデックスと組み合わせて、主キーに[TenantIsolationId]
のみを利用するほうがよいでしょう。私の考えには欠陥がありますか?
私はまだスキーマの開発の初期段階にあるので、最初のスケッチが完了したら、大量のダミーデータを使用して多くのパフォーマンステストを実行します。しかし、一般的な慣行として、このシナリオでは何が推奨されますか?
さらに、高レベルのデータ分離を保証する必要のあるマルチテナントデータベースアーキテクチャを一般的にカプセル化している場合、2値のキーの組み合わせを利用することに傾倒しない大きな前進がありましたか?私は主に SalesforceのMulitenant Magic Webinar と GoogleのF1ホワイトペーパー を参照して、このトピックについてよく読んで見ました。最近の記事は、まだ彼らの年齢でも概説した概念に従っている傾向があり、私はSalesforceとAdWordsのスケールに近いどこにもないデータベースのスキーマを構築している間、私はそれらの原則に傾いていることに気づきます共鳴した。
しかし、一般的な慣行として、このシナリオでは何が推奨されますか?
ここでは、テナントごとのデータベースがベストプラクティスです。実用的でないシナリオもありますが、SQL Serverでマルチテナントシステムを設計する際のstrong設定にする必要があります。
テナントごとのデータベースにより、次のことが可能になります。
検証可能で販売しやすい優れたセキュリティとデータ分離。
最適なパフォーマンス、共有クエリプランなし。
それ以外:
TenantIsolationIDのポイントは何ですか?
テナントデータを含むすべてのクラスター化インデックスにTenantIDを含める必要があります。
パーティション化に使用している場合を除いて、これは先行列である必要があります。その場合、後続列にすることができます。
単一のデータベースをスケールプランとして小さなデータベースに分割することを計画する必要があります。ただし、分割は一方向の操作になる場合があります。
TenantIDがINTであるかUNIQUEIDENTIFIERであるかは、インデックスサイズにのみ関係します。 UNIQUEIDENTIFIERを使用すると、すべてのセカンダリインデックスが大きくなります。しかし、それは大きなコストではありません。断片化とページ分割は、ここでは大した問題ではありません。テーブルに複数の挿入ポイントがあることによるパフォーマンスへの影響の詳細については、 適切なページ分割と順次GUIDキー生成 を参照してください。
そこにTenantIsolationID
UniqueIdentifierを置く目的がわかりません。それを削除するか、質問でそれの明確な目的を説明することをお勧めします。 IDENTITY値を公開しないようにクライアントに与えることができる外部IDを使用する場合、TenantIsolationID
はTenant
テーブルにのみ存在し、他の。そして、その場合、誰かがログインしたときに一度検索され、検索されたTenantID
はキャッシュされ、それ以降使用されます。
TenantID
をクラスター化インデックスの最初に配置する必要があるというのが最初の直感でした(それがPKかどうかに関係なく)。
潜在的なパフォーマンスの落とし穴を含む、これに対処するための追加の詳細については、非常によく似た質問に対する私の回答を参照してください。ここでもDBA.SEにあります。
alwaysについて、TenantID
、またはTenantID, TenantIsolationID
複合キー:顧客がお互いのデータを見てほしくないので、はい、これがmostの場合です。ただし、X日/月/年以上のレコードのガベージコレクションなど、テナントごとではないメンテナンス操作は引き続き行われます。それらの場合は、作成日の先頭列または特定のテーブルに関連するもので非クラスター化インデックスを作成できます。