web-dev-qa-db-ja.com

共有エンティティの正規化と制約の適用

異なるエンティティ間で共有され、多くのエンティティの1つと関係があるエンティティに関する特定の「ベストプラクティス」または「パターン」を探しています。

たとえば、顧客、サプライヤ、従業員などの共通の住所フィールドを格納するために使用できる汎用エンティティ「Address」がある場合があります。

ベテランのDBAはそのルートを取るのでしょうか、それとも対応するエンティティにフィールドを追加するのでしょうか。また、保守性や、エンティティによって(将来的に)異なる可能性のある制約などについても考えています。

このテーマに関する権威ある、または確立された作品への参照を取得したいと思います。

2
Louis Somers

信頼できるものを指摘することはできませんが、そのような実装の詳細を考えれば、潜在的な欠点は明らかです。

「共有」子会社テーブルを持つことは、主に2つの「親」テーブル(たとえば、CustomerEmployee)が両方とも同じAddressテーブルを使用してアドレスを格納する場合、外部キー制約を使用できないため、問題があります。アドレスレコードと対応する親レコード間の参照整合性を確保するため。

外部キー制約の使用を控えたとしても、外部キー列を設定する際にいくつかの難問があります。基本的に3つのオプションがありますが、どれも理想的ではありません。

  1. CustomerテーブルとEmployeeテーブルにAddressIDフィールドを配置します。ここでの問題は、(1)住所が複数回使用されないことを保証できないこと、および(2)AddressIDが自動割り当てされている場合、住所をCustomer/Employeeテーブルに保存できないことです。アドレスが作成されます。これは、おそらくレコードを挿入する方法とは逆です(ieAddressを「親」テーブルにします)。

  2. CustomerID列とEmployeeID列をAddressテーブルに配置します。ここでの問題には、(1)アドレスの二重使用を保証できない、(2)いずれかの列にNULLを格納しているためにスペースを浪費する、(3)拡張性が低いなどがあります。アドレスを必要とするエンティティが増えるにつれて。

  3. CustomerID/EmployeeID/etcを折りたたみます。単一の列ParentIDと、ParentTypeIDCustomersを区別する別の列Employeesに分けます。これは上記の(2)よりも拡張性が高くなりますが、ParentTypeIDに親テーブルの「マジックナンバー」を割り当てる必要があるなど、独自の問題があります。

そのようなアプローチが実用的でない場所はないとは言いませんが、複数のテーブルに同様の列を配置することが本当に大したことであるかどうか、そしてそれらを共通のテーブルに移動しようとする場合は本当に考慮する必要があります挿入、更新、結合などの複雑さが増すために何でも購入できます。私見では、通常、各テーブルには他のテーブルとの関係に明確な制約があり、「親」テーブルは作成中のコアビジネスオブジェクトを表す方がよいでしょう。 (顧客、従業員など)、他のいくつかのテーブルに共通する補助的な複合タイプではありません。

4
richardtallent

あらゆる種類のアドレスを単一のテーブルに積み上げる動機は、通常、コードの再利用の概念の誤解と誤用です。

共通の属性セットを持つ2つのエンティティがあるため、それらの属性は独自のテーブルに属していると誤解する可能性があります。エンティティの列が類似または同一である場合があります偶然に。データベース内のすべてのNAMEまたはDESCRIPTIONまたはEFFECTIVE_DATEに対してテーブルを作成することはありません。少なくとも、これを実行したくないと思います。

一部の人々は、列を削除するすべてのインスタンスを誤って正規化と呼んでいます。正規化には、独自のテーブルへの列の削除が含まれますが、この方法で列を削除するすべてのインスタンスが実際に正規化されるわけではありません。正規化では、テーブルから列を削除する非常に具体的な理由が規定されています。これらの理由のいずれにも当てはまらない場合は、正常化していないだけで、物事を複雑にしているだけです。

これについては、2つの正しい考え方があります。アドレスを含む複数のエンティティサブタイプの共通機能をすべて組み込んだエンティティスーパータイプがあるため、アドレスがすべて1つの山に属しているか、またはアドレスが別々の山に属している。 (テーブル)アドレスを持つものの種類ごとに、アドレステーブルごとに実装されているIAddressインターフェイスに対して手続き型コードを記述します。

実際にエンティティスーパータイプがある場合、たとえばCUSTOMERVENDOREMPLOYEEなどのサブタイプを持つLEGAL_ENTITYの場合、ADDRESSテーブルがあります。つまり、LEGAL_ENTITYの子は正当なアプローチです。法人が移転したときに複数の場所ではなく一度だけ住所を変更できるため、顧客、ベンダー、従業員(または追跡しているもの)の間に大きな重複がある場合でも、これは価値のあるアプローチになる可能性があります。一方、そのようなスーパータイプを持っていない場合は、リチャード・タレントが指摘した問題に直面することになります。

アドレスを所有しているエンティティのタイプに応じて異なるテーブルにアドレスを保持している場合でも、使用している言語がインターフェイスをサポートしていれば、コードの再利用を実現できます。

余談ですが、tvCaはコメントで、アドレスは別のテーブルの行としてではなく列として格納される可能性があると指摘しました。これは、各エンティティに必要なアドレスの数に大きく依存します。 2つの住所(物理的、郵送)を追跡している場合、または住所履歴を保存している場合は、住所テーブルを使用します。宛先ごとに1つのアドレスのみを格納する場合、別のテーブルはやり過ぎになる可能性があります。

5
Joel Brown