多くのサブタイプ(さまざまな種類の記録されたイベント)を持つエンティティ(イベント)を表す非常に大きな(数百万行)テーブルがあります。各行はID(obj_id
)で識別され、イベントのタイプを記録する属性obj_type
があります。
すべてのサブタイプは、最も重要な属性(メインテーブルで表される)を共有しますが、それらのいくつか(少数派)は、追加の子テーブルで表される追加の属性を持っています。
メインテーブルの行を含む新しいリレーションシップを表す必要があります。たとえば、タイプ 'A'のイベントがタイプBのイベントとタイプ 'C'または 'D'のイベントに関連しているか、タイプ 'X'または 'Y'のイベントがタイプ「Z」のイベント。
以下の2つのスキーマのどちらが優れていますか? (2つのうちのいずれかはお勧めできませんか?)
スキーマ1:
create table supertype(
obj_id varchar2(30) primary key,
obj_type varchar2(1) check (obj_type in ('A','B','C','D',..)),
attribute1 varchar2(1),
attribute2 varchar2(1),
attribute3 varchar2(1),
...
attributen varchar2(1)
)
create table relation_A_with_B_and_cd(
obj_id_subtype_A varchar2(30) primary key references supertype(obj_id),
obj_id_reference_to_subtype_B varchar2(30) references supertype(obj_id),
obj_id_reference_to_subtype_C_or_D varchar2(30) references supertype(obj_id),
attribute_det_a1 varchar2(1),
attribute_det_a2 varchar2(1),
)
create table relation_XY_with_Z(
obj_id_subtype_X_or_Y varchar2(30) primary key references supertype(obj_id),
obj_id_reference_to_subtype_Z varchar2(30) references supertype(obj_id),
attribute_1 varchar2(1),
attribute_2 varchar2(1),
)
スキーマ2:
create table supertype(
obj_id varchar2(30) primary key,
obj_type varchar2(1) check (obj_type in ('A','B','C','D',...)),
attribute1 varchar2(1),
attribute2 varchar2(1),
attribute3 varchar2(1)
)
alter table supertype add constraint UQ_type unique(obj_id,obj_type)
create table relation_A_with_B_and_cd(
obj_id_subtype_A varchar2(30) primary key ,
obj_type_subtype_A varchar2(1) check (obj_type in ('A')),
obj_id_reference_to_subtype_B varchar2(30) ,
obj_type_reference_to_subtype_B varchar2(1) check (obj_type_reference_to_subtype_B in ('B')),
obj_id_reference_to_subtype_CD varchar2(30) ,
obj_type reference_to_subtype_CD varchar2(1) check (obj_type reference_to_subtype_CD in ('C','D')),
attribute_det_a1 varchar2(1),
attribute_det_a2 varchar2(1),
constraint fk_subtype_a foreign key (obj_id_subtype_A,obj_type_subtype_A) references supertype (obj_id,obj_type),
constraint fk_ref_subtype_B foreign key (obj_id_reference_to_subtype_B ,obj_type_reference_to_subtype_B) references supertype (obj_id,obj_type),
constraint fk_ref_subtype_CD foreign key (obj_id_reference_to_subtype_CD ,obj_type_reference_to_subtype_CD) references supertype (obj_id,obj_type),
)
create table relation_XY_with_Z(
obj_id_subtype_XY varchar2(30) primary key,
obj_type_subtype_XY varchar2(1) check (obj_type in ('X','Y')),
obj_id_reference_to_subtype_Z varchar2(30) ,
obj_type_reference_to_subtype_Z varchar2(1) check (obj_type reference_to_subtype_Z in ('Z')),
attribute_1 varchar2(1),
attribute_2 varchar2(1),
constraint fk_subtype_XY foreign key (obj_id_subtype_XY,obj_type_subtype_XY) references supertype (obj_id,obj_type),
constraint fk_ref_subtype_Z foreign key (obj_id_reference_to_subtype_Z ,obj_type reference_to_subtype_X) references supertype (obj_id,obj_type)
)
考慮事項
2番目のものは一部の情報を複製しますが、制約により、関係のオブジェクトIDが正しいサブタイプであることを確認します。ただし、(obj_id,obj_type)
は既に主キーであるため、これは最小キーではないため、一意のobj_id
を宣言するのは困惑します。
最初のものは、データを複製しませんが、関係に参加しているイベントタイプの正しさのチェックを実行しません。
エンティティのサブタイプを実装する場合、Oracleにはさまざまなソリューションがあります。
ここでは、オプション2を提案しています。オプション2は、列の点でマスターテーブルを狭く保ち、ストレージを節約する可能性があります。ただし、宣言的に、またはPL/SQLトリガーなどを使用してビジネスルールを適用する場合は、重大な欠点があります。
非常に大きなテーブルとオプション2の場合、堅牢なデータベースが好きな場合でも、宣言的な制約を使用しないことをお勧めします。非常に遅くなる可能性があります。ロックのためにインデックスを適切に割り当てる必要があり、大量の並列ロードはパフォーマンスと並列化の点で難しい場合があります。
非常に大きなテーブルの場合は、オプション3またはオプション1のいずれかをお勧めします。オプション1は理解するのがかなり簡単で、Oracleが1つのテーブルで許可する列の数が多い場合、問題にはなりません。ストレージは問題になりません。後続のnull列はデータブロックにまったく格納されず、行自体のnull値は、「こんにちは、この列には値がありません」と通知するために列ごとに1バイトのみ必要です。オプション1の場合、1つ以上のサブタイプのみを選択する、パフォーマンスが高く並列化可能なビューを作成できます。オプション1は、並列で高速にロードすることもできます。また、行のチェック制約としてfkを必要とする多くのルールを実装できます。これには、大量の使用を妨げるロックやその他の問題は含まれません。
もちろん、サブタイプの1つが他のサブタイプと比較して非常に広い列を持っている場合を除きます。これにより、各データブロックに含まれる行がかなり少なくなります。その場合、オプション3をお勧めします。これは、それらが非常に異なるため、スーパータイプ全体でクエリを実行するために「union all」構造を使用するためです。組み合わせは、オプション3とオプション1:多くのデータ(varchar2(4000)が適切に入力された)を含むオプションの列を持つサブタイプのオプション3と、他のサブタイプのオプション1です。