デザインパターン-多くの親テーブルの1つ


13

特定のテーブルが多数の異なる親テーブルの1つにFKできるデータベースの状況に頻繁に出くわします。この問題に対する2つの解決策を見てきましたが、どちらも個人的に満足できるものではありません。私はあなたがそこに見た他のどのようなパターンに興味がありますか?それを行うためのより良い方法はありますか?

不自然な例
システムが持っているとしましょうAlerts。アラートは、顧客、ニュース、製品などのさまざまなオブジェクトに対して受信できます。特定のアラートは、1つだけのアイテムに対応できます。何らかの理由で、顧客、記事、製品は動きが速い(ローカライズされている)ため、アラートの作成時に必要なテキスト/データをアラートに取り込むことはできません。このセットアップを考えると、2つのソリューションを見てきました。

注:以下のDDLはSQL Server用ですが、私の質問はどのDBMSにも当てはまります。

解決策1-複数のNullable FKey

このソリューションでは、1対多のテーブルにリンクするテーブルに複数のFK列があります(簡潔にするため、以下のDDLにはFKの作成は示されていません)。 良い -このソリューションでは、外部キーを持っていると便利です。FKのヌル最適性により、この便利で正確なデータを比較的簡単に追加できます。BADクエリは、関連付けられたデータを取得するためにN LEFT JOINSまたはN UNIONステートメントを必要とするため、優れていません。SQL Serverでは、特にLEFT JOINSにより、インデックス付きビューの作成ができなくなります。

CREATE TABLE Product (
    ProductID    int identity(1,1) not null,
    CreateUTC    datetime2(7) not null,
     Name        varchar(100) not null
    CONSTRAINT   PK_Product Primary Key CLUSTERED (ProductID)
)
CREATE TABLE Customer (
    CustomerID  int identity(1,1) not null,
    CreateUTC   datetime2(7) not null,
     Name       varchar(100) not null
    CONSTRAINT  PK_Customer Primary Key CLUSTERED (CustomerID)
)
CREATE TABLE News (
    NewsID      int identity(1,1) not null,
    CreateUTC   datetime2(7) not null,
    Name        varchar(100) not null
    CONSTRAINT  PK_News Primary Key CLUSTERED (NewsID)
)

CREATE TABLE Alert (
    AlertID     int identity(1,1) not null,
    CreateUTC   datetime2(7) not null,
    ProductID   int null,
    NewsID      int null,
    CustomerID  int null,
    CONSTRAINT  PK_Alert Primary Key CLUSTERED (AlertID)
)

ALTER TABLE Alert WITH CHECK ADD CONSTRAINT CK_OnlyOneFKAllowed 
CHECK ( 
    (ProductID is not null AND NewsID is     null and CustomerID is     null) OR 
    (ProductID is     null AND NewsID is not null and CustomerID is     null) OR 
    (ProductID is     null AND NewsID is     null and CustomerID is not null) 
)

ソリューション2-各親テーブルに1つのFK
このソリューションでは、各「親」テーブルにアラートテーブルへのFKがあります。親に関連付けられたアラートを簡単に取得できます。マイナス面として、アラートから参照者への実際のチェーンはありません。さらに、データモデルは孤立したアラートを許可します。アラートは、製品、ニュース、または顧客に関連付けられていません。繰り返しますが、複数のLEFT JOINを使用して関連付けを見つけます。

CREATE TABLE Product (
    ProductID    int identity(1,1) not null,
    CreateUTC    datetime2(7) not null,
     Name        varchar(100) not null
    AlertID     int null,
    CONSTRAINT   PK_Product Primary Key CLUSTERED (ProductID)
)
CREATE TABLE Customer (
    CustomerID  int identity(1,1) not null,
    CreateUTC   datetime2(7) not null,
     Name       varchar(100) not null
    AlertID     int null,
    CONSTRAINT  PK_Customer Primary Key CLUSTERED (CustomerID)
)
CREATE TABLE News (
    NewsID      int identity(1,1) not null,
    CreateUTC   datetime2(7) not null,
    Name        varchar(100) not null
    AlertID     int null,
    CONSTRAINT  PK_News Primary Key CLUSTERED (NewsID)
)

CREATE TABLE Alert (
    AlertID     int identity(1,1) not null,
    CreateUTC   datetime2(7) not null,
    CONSTRAINT  PK_Alert Primary Key CLUSTERED (AlertID)
)

これは関係データベースの単なる寿命ですか?より満足できる代替ソリューションはありますか?


1
次の列を持つ1つの親テーブルAlertableを作成できます:ID、CreateDate、Name、Type。3つの子テーブルにFKを設定できます。ALertはAlertableという1つのテーブルにのみFKを設定します。
AK

いくつかのケースでは、あなたが良い点を示します-効果的に解決策3。ただし、データが高速で移動またはローカライズされている場合はいつでも機能しません。たとえば、Product、Customer、およびNewsにはそれぞれ、対応する「Lang」テーブルがあり、複数の言語でNameをサポートするとします。ユーザーの母国語で「名前」を配信する必要がある場合、に保存できませんAlertable。それは理にかなっていますか?
EBarr

1
@EBarr:「ユーザーの母国語で「名前」を配信する必要がある場合、アラート可能に保存できません。それは理にかなっていますか?」いいえ、そうではありません。現在のスキーマで、ユーザーの母国語で「名前」を配信する必要がある場合、Product、Customer、またはNewsテーブルに保存できますか?
ypercubeᵀᴹ

@ypercubeこれらの各テーブルには、関連付けられた言語テーブルがあることを追加しました。「名前」のテキストはリクエストごとに異なる可能性があるため、Alertableに保存できないシナリオを作成しようとしました。
EBarr

既に受け入れられている名前がない限り、すべてのアラートとその関連する親を表示するために行うクエリに対して、「タコ結合」という用語を提案します。:)
ネイサンロング

回答:


4

2番目のソリューションは、1つの(オブジェクト)対多(アラート)の関係を提供しないため、適用できないと理解しています。

3NFに厳密に準拠しているため、たった2つのソリューションに固執しています。

私はより少ない結合スキーマを設計します:

CREATE TABLE Product  (ProductID  int identity(1,1) not null, ...)
CREATE TABLE Customer (CustomerID int identity(1,1) not null, ...)
CREATE TABLE News     (NewsID     int identity(1,1) not null, ...)

CREATE TABLE Alert (
  -- See (1)
  -- AlertID     int identity(1,1) not null,

  AlertClass char(1) not null, -- 'P' - Product, 'C' - Customer, 'N' - News
  ForeignKey int not null,
  CreateUTC  datetime2(7) not null,

  -- See (2)
  CONSTRAINT  PK_Alert Primary Key CLUSTERED (AlertClass, ForeignKey)
)

-- (1) you don't need to specify an ID 'just because'. If it's meaningless, just don't.
-- (2) I do believe in composite keys

または、整合性関係が必須である場合、次のように設計できます。

CREATE TABLE Product  (ProductID  int identity(1,1) not null, ...)
CREATE TABLE Customer (CustomerID int identity(1,1) not null, ...)
CREATE TABLE News     (NewsID     int identity(1,1) not null, ...)

CREATE TABLE Alert (
  AlertID     int identity(1,1) not null,
  AlertClass char(1) not null, /* 'P' - Product, 'C' - Customer, 'N' - News */
  CreateUTC  datetime2(7) not null,
  CONSTRAINT  PK_Alert Primary Key CLUSTERED (AlertID)
)

CREATE TABLE AlertProduct  (AlertID..., ProductID...,  CONSTRAINT FK_AlertProduct_X_Product(ProductID)    REFERENCES Product)
CREATE TABLE AlertCustomer (AlertID..., CustomerID..., CONSTRAINT FK_AlertCustomer_X_Customer(CustomerID) REFERENCES Customer)
CREATE TABLE AlertNews     (AlertID..., NewsID...,     CONSTRAINT FK_AlertNews_X_News(NewsID)             REFERENCES News)

とにかく...

3つの有効なソリューションに加えて、多くの(オブジェクト)対1(アラート)関係で考慮される別のソリューション...

これらは、道徳とは何ですか?

それらは微妙に異なり、基準に同じ重みがあります:

  • 挿入および更新のパフォーマンス
  • クエリの複雑さ
  • 収納スペース

だから、あなたにそのcomfierを選択してください。


1
入力いただきありがとうございます。あなたのコメントのほとんどに同意します。それは構成された例であるため、おそらく必要な関係(あなたの目にはソリューション2を除く)を巧妙に説明しました。 fn1-わかった、私は単にテーブルを単純化して問題に焦点を当てていた。fn2-複合キーと私は帰ります!単純な結合スキーマについては簡単ですが、個人的には可能な限りDRIを使用して設計してみてください。
-EBarr

これを見直して、私は自分の解決策の正しさを疑い始めました...とにかく、それは2回投票されました。私は「n」の組合/加入が...対処されていないとして、私のデザインは、有効ですが、与えられた問題に適していないと信じていますが
マーカス・ヴィニシウスポンペウ

DRIの頭字語は私にわかりました。すべての人にとって、それは宣言的参照整合性、参照データ整合性の背後にあるテクニックで、一般的に...(ドラムロール)... DDL FOREIGN KEYステートメントとして実装されます。en.wikipedia.org/wiki/Declarative_Referential_Integrityおよびmsdn.microsoft.com/en-us/library/…の
マーカスビニシウスポンペ

1

トリガーで維持される結合テーブルを使用しました。データベースのリファクタリングが不可能または望ましくない場合、このソリューションは最後の手段として非常にうまく機能します。RIの問題を処理するためだけのテーブルがあり、すべてのDRIがそれに反するという考え方です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.