データベースにある種の多態性の関連付けを実装する必要があるインスタンスがたくさんあります。私はいつもすべてのオプションを何度も考え直して、膨大な時間を無駄にしています。ここに私が考えることができる3つがあります。 SQL Serverのベストプラクティスがあることを願っています。
これは複数列のアプローチです
これは外部キーなしのアプローチです
そして、これがベーステーブルアプローチです
最も一般的な2つのアプローチは、クラスごとのテーブル(つまり、基本クラスのテーブルと、サブクラスを説明するために必要な追加の列を含む各サブクラスごとの別のテーブル)と階層ごとのテーブル(つまり、1つ以上の1つのテーブルのすべての列)です。サブクラスの区別を可能にする列。どちらがより良いアプローチであるかは、実際にはアプリケーションの詳細とデータアクセス戦略に依存します。
最初の例では、FKの方向を逆にし、親から余分なIDを削除することで、クラスごとのテーブルを作成します。他の2つは基本的にクラスごとのテーブルのバリアントです。
このモデルのもう1つの一般的な名前は、スーパータイプモデルです。このモデルには、別のエンティティに結合することで拡張できる属性の基本セットがあります。 Oracleの本では、論理モデルと物理実装の両方として説明されています。リレーションなしのモデルでは、データが無効な状態に成長する可能性があります。孤立レコードは、そのモデルを選択する前にニーズを強く検証します。ベースオブジェクトにリレーションが保存されている最上位モデルではnullが発生し、フィールドが相互に排他的である場合は常にnullが発生します。子オブジェクトでキーが適用されている下部の図では、nullは削除されますが、従属関係がソフトな依存関係になり、カスケードが適用されなかった場合は孤立が許可されます。これらの特性を評価することで、最適なモデルを選択するのに役立つと思います。私は過去に3つすべてを使用しました。
私は同様の問題を解決するために次の解決策を使用しました:
多対多ベースの設計:関係はObjectNと何かの間の1対多ですが、リレーションテーブルのPKを変更した多対多の関係と同等です。
まず、ObjectNとオブジェクトごとの何かの間の関係テーブルを作成し、次にSomething_ID列をPKとして使用します。
これは、SomethingとObject1の関係のDDLであり、Object2とObject3でも同じです。
CREATE TABLE Something
(
ID INT PRIMARY KEY,
.....
)
CREATE TABLE Object1
(
ID INT PRIMARY KEY,
.....
)
CREATE TABLE Something_Object1
(
Something_ID INT PRIMARY KEY,
Object1_ID INT NOT NULL,
......
FOREIGN KEY (Something_ID) REFERENCES Something(ID),
FOREIGN KEY (Object1_ID) REFERENCES Object1(ID)
)
このチケットの他の可能なオプションの詳細と例 multiple-foreign-keys-for-the-same-business-rule
ベーステーブルアプローチと呼んでいるものを使用しました。たとえば、名前、住所、電話番号のテーブルがあり、それぞれにPKとしてのIDがあります。次に、メインエンティティテーブルentity(entityID)とリンクテーブルattribute(entityKey、attributeType、attributeKey)があり、attributeKeyは、attributeTypeに応じて、最初の3つのテーブルのいずれかを指すことができます。
いくつかの利点:エンティティごとに好きなだけ名前、住所、電話番号を使用できる、新しい属性タイプを簡単に追加できる、極端な正規化、共通の属性を簡単にマイニングできる(つまり、重複する人物を特定できる)、その他のビジネス固有のセキュリティ上の利点
短所:単純な結果セットを作成するための非常に複雑なクエリにより、管理が困難になりました(つまり、十分なT-SQLチョップを持つ人を雇うのに苦労しました)。パフォーマンスは一般的なものではなく、非常に特定のユースケースに最適です。クエリの最適化には注意が必要です
ずっと長いキャリアを経て数年間この構造で暮らしていたので、同じ奇妙なビジネスロジックの制約とアクセスパターンがない限り、もう一度使用することをためらっています。一般的な使用法については、型付きテーブルでエンティティを直接参照することを強くお勧めします。つまり、Entity(entityID)、Name(NameID、EntityID、Name)、Phone(PhoneID、EntityID、Phone)、Email(EmailID、EntityID、Email)です。データの繰り返しと一般的な列がいくつかありますが、プログラミングと最適化ははるかに簡単です。
アプローチ1が最適ですが、somethingとobject1、object2、object3の関連付けは1対1である必要があります。
つまり、子(object1、object2、object3)テーブルのFKは、null以外の一意キーまたは子テーブルの主キーである必要があります。
object1、object2、object3は、Polymorphicオブジェクトの値を持つことができます。
私によると、あなたの最初のタイプのアプローチは、データだけでなくクラスも定義できる最善の方法ですが、すべての主要なデータが子供のために役立つはずです。
したがって、要件を確認してデータベースを定義できます。
複数の列の外部キーを使用するアプローチ1が最適です。これにより、他のテーブルとの事前定義された接続を確立できるため、スクリプトによるデータの選択、挿入、更新がはるかに簡単になります。
これを達成するための単一または普遍的なベストプラクティスはありません。それはすべて、アプリケーションが必要とするアクセスのタイプに依存します。
私のアドバイスは、これらのテーブルへのアクセスの予想されるタイプの概要を作成することです:
この質問への回答に基づいて、適切な解決策を見つけることができます。
サブクラスに固有のプロパティを格納するためのもう1つの可能性は、名前と値のペアを持つテーブルを使用することです。このアプローチは、多数の異なるサブクラスがある場合、またはサブクラスの特定のフィールドが頻繁に使用されない場合に特に役立ちます。
私は最初のアプローチを使用しました。極端な負荷がかかると、「Something」テーブルがボトルネックになります。
テーブル定義の最後に属性の特殊化を追加して、さまざまなオブジェクトにテンプレートDDLを使用するアプローチを採用しました。
DBレベルで、さまざまなクラスを「何か」のレコードセットとして本当に表現する必要がある場合は、それらの上にビューを配置します
SELECT "Something" fields FROM object1
UNION ALL
SELECT "Something" fields FROM object2
UNION ALL
SELECT "Something" fields FROM object3
問題は、3つの独立したオブジェクトがある場合に、衝突しない主キーをどのように割り当てるかです。通常、人々はUUID/GUIDを使用しますが、私の場合、キーは衝突を避けるために時間とマシンに基づいてアプリケーションで生成された64ビット整数でした。
このアプローチをとれば、「Something」オブジェクトがロック/ブロックを引き起こす問題を回避できます。
「Something」オブジェクトを変更する場合は、3つの独立したオブジェクトがあり、そのすべてを変更する必要があります。
要約すると。ほとんどの場合、オプション1で問題なく動作しますが、負荷が非常に高い場合、ロックブロッキングが発生し、デザインを分割する必要があります。