web-dev-qa-db-ja.com

基本的なRDBMSテーブルの関係

「マスターテーブル」と複数の「サブテーブル」の設計がある場合は、マスターテーブルが各サブテーブルに「リンク」するか、サブテーブルがマスターにリンクするか、双方向リンクを確立する方がよい*。 ?サブテーブルに存在するデータは存在しない可能性があります(つまり、特定のエントリに関連していない可能性があるため、サブテーブルにリンクされたエントリは作成されません)。基本的に、データは1対(0または1)の方法で関連付けられます。マスターテーブルを使用せずにサブテーブル間をリンクする理由はありません。

具体的には、MS SQL Server(2008R2 +)に関してより良い*ことを懸念しています。

デザイン例1:マスターテーブルからサブテーブルへのリンク

CREATE TABLE tMaster (
  PK_TM int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED
  ,IntrinsicField1 datetime NOT NULL
  ,IntrinsicField2 int NOT NULL
  ,IntrinsicField3 nvarchar(255) NULL
  ,index_subA int NULL --index created on this value. links to PK_SA of appropriate entry if it exists
  ,index_subB int NULL --index created on this value
  ....
  ,index_subM int NULL --index created on this value
)
CREATE TABLE tSubA
  PK_SA int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED
  ,ExtraField1 int NOT NULL
  ,ExtraField2 varchar(24) NOT NULL
) 
CREATE TABLE tSubB
  PK_SB int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED
  ,ExtF1 NUMERIC(5,3) NOT NULL
  ,ExtF2 NUMERIC(5,3) NOT NULL
) 
CREATE TABLE tSubM
  PK_SM int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED
  ,EField1 int NOT NULL
  ,EField2 nvarchar(100) NOT NULL
)

デザイン例2:サブテーブルはマスターテーブルにリンクしています

CREATE TABLE tMaster (
  PK_TM int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED
  ,IntrinsicField1 datetime NOT NULL
  ,IntrinsicField2 int NOT NULL
  ,IntrinsicField3 nvarchar(255) NULL
)
CREATE TABLE tSubA
  lMaster_ID int NOT NULL PRIMARY KEY CLUSTERED -- value of PK_TM of cross-linked entry
  ,ExtraField1 int NOT NULL
  ,ExtraField2 varchar(24) NOT NULL
)
CREATE TABLE tSubB
  lMaster_ID int NOT NULL PRIMARY KEY CLUSTERED
  ,ExtF1 NUMERIC(5,3) NOT NULL
  ,ExtF2 NUMERIC(5,3) NOT NULL
  ,Master_ID int NOT NULL --index created on this value. links to PK_TM of appropriate entry
) 
CREATE TABLE tSubM
  lMaster_ID int NOT NULL PRIMARY KEY CLUSTERED
  ,EField1 int NOT NULL
  ,EField2 nvarchar(100) NOT NULL
)

デザイン例3:双方向リンク

CREATE TABLE tMaster (
  PK_TM int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED
  ,IntrinsicField1 datetime NOT NULL
  ,IntrinsicField2 int NOT NULL
  ,IntrinsicField3 nvarchar(255) NULL
  ,index_subA int NULL --index created on this value. links to PK_SA of appropriate entry if it exists
  ,index_subB int NULL --index created on this value
  ....
  ,index_subM int NULL --index created on this value
)
CREATE TABLE tSubA
  PK_SA int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED
  ,ExtraField1 int NOT NULL
  ,ExtraField2 varchar(24) NOT NULL
  ,lMaster_ID int NOT NULL
) 
CREATE TABLE tSubB
  PK_SB int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED
  ,ExtF1 NUMERIC(5,3) NOT NULL
  ,ExtF2 NUMERIC(5,3) NOT NULL
  ,lMaster_ID int NOT NULL
) 
CREATE TABLE tSubM
  PK_SM int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED
  ,EField1 int NOT NULL
  ,EField2 nvarchar(100) NOT NULL
  ,lMaster_ID int NOT NULL
)

*より良いかもしれません

  1. もっと早く
  2. dBエントリが追加されたり、ときどき削除されたりするため、時間の経過とともに急増する可能性が低くなります
  3. 他のDBAがすぐに理解しやすい
  4. 平均的なエ​​ンドユーザーにとってより直感的
  5. サブテーブルタイプを追加することで、より簡単に拡張できます
  6. より多くのデータコンパクト
  7. サブテーブルの多くのコピーに対して1つのマスターになるように簡単に変更できます
  8. サブテーブルの単一のコピーに多くのマスターになるように、より簡単に変更できます
  9. ここに独自の定義を挿入します

(ここではオプション7と8をあまり重視していません)

2
mpag

ここで話すことはあまりありません。少なくとも、一般通念は非常に明確です。データベースの実際の経験から生まれた非常に正当な理由がない限り、オプション2のみを検討する必要があります。

オプション1とオプション3のどちらにも、第一正規形(1NF)の親テーブルはありません。これは、繰り返し列、つまりサブテーブルへの外部キーが含まれているためです。

トランザクションシステムでは、テーブルが少なくとも3NFにある必要があるという仮定から始める必要があります。正当でよく考えられた理由のためだけにそれから離れてください。

そのような理由の1つmightは、サブテーブルがたくさんあり、どのサブテーブルを親に結合する必要があるかわからないためです。特定の親レコード。多くの要因によっては、パフォーマンスの問題が発生する可能性があります。この問題が発生した場合に使用できる妥協案の1つは、オプション4と見なすことができます。これは、各タイプの子の存在を示すビットフラグを親テーブルに配置することです。これは、最終的なデータの不整合の問題をまだ懇願していますが、誤ったレコードではなく空の結合のみを指すリスクがあるため、少なくともオプション3よりも整合性が低くなります。

3
Joel Brown

私は個人的にオプション2を好み、過去に何度もこの設計を使用しました。特に、コードで継承が機能するのと同様の階層をモデル化しようとしている場合はそうです。

オプション2を好む理由は、マスターテーブルをクリーンに保つためです。 Object-Oriented-Programmingで継承を実装する場合、基本クラスはそれから派生するクラスについて何も知らないはずです。これを知っていると、考えられるすべてのタイプのサブクラスの参照を追加する必要があるため、オプション1と3をすぐに割引できます。これは、変更が必要な頻度によっては、維持するのが非常に困難になります。オプション2を使用すると、既存のクエリを壊す可能性が低くなるため、サブクラスをさらに簡単に追加できます。

さらに、オプション3を割引します。これは、必要以上にキーを保存する必要があり、それらの列にFOREIGN KEY制約を設定する場合(必要に応じて)、データベースエンジンにより、保存できないためです。循環参照が発生します。

また、FOREIGN KEY制約をON DELETE CASCADEに設定すると、親レコードがないとサブクラスレコードが存在しなくなります。私は通常、この機能を使用せず、一般的にはお勧めしませんが、これは実際に機能し、デッドレコードの保守がはるかに簡単になる良いケースです。

すべての「共有」プロパティをマスターテーブルの列として保持し、サブクラステーブル内のサブクラスに固有のプロパティのみを含めると、必要なストレージを最小限に抑えることができます。

速度に関しては、ハードウェアとデータサイズ/行数がわからないのは主観的ですが、単一のテーブル(サブクラスからマスター)に結合すると、コードを理解し、維持し、最適化するのが、オプション3などのより複雑な例。

2
Mr.Brownstone