web-dev-qa-db-ja.com

参照整合性-「深さ」の間接外部キー

質問

「Grand-Parent」または「Great Grand-Parent」テーブルのキーが複数のリレーションシップツリーから作成されるときに維持されるためのベストプラクティスは何ですか。

その質問は意味をなさそうにないので詳細

私たちの環境で実行されている自動化プロセスの実行ステータスを追跡するためのデータベースを構築しようとしています。

一般に、1つ以上の「実行可能ファイル」をトリガーする「ジョブ」があり、それらの「実行可能ファイル」は1人以上の顧客のタスクを実行できます。次に、2つのロギングテーブルを作成します。1つは「ジョブ」がいつ開始されたかを追跡し、もう1つは各「ExecutableCustomer」インスタンスの成功と失敗のステータスを記録します。

計画された簡略化されたスキーマは以下の通りです: ER Diagram

レコードをJobExecutableCustomerExecutionLogに修正するとき、Job.ID値に関連付けられたJobExecutionLog.ID値がJob.IDに関連付けられたJobExecutableCustomer.ID値と一致することを確認します。

通常、私はForeign Keyを使用してこれを処理しますが、Job.IDJobExecutableCustomerJobExecutableCustomerExecutionLogにもJobExecutionLogにも保存されないためです。関係は間接的です。

例:

「メールを送信」と「テキストメッセージを送信」の2つのジョブがあります。 「Send Email」は、1人の顧客に属する単一の実行ファイルを開始します。 「テキストメッセージの送信」には2つの実行可能ファイルがあります(両方とも同じ顧客に対して実行されます)。 「Send Email」のレコードがJobExecutableCustomerExecutionLogに書き込まれるときに、Job.IDおよびJobExecutableCustomerExecutionLog.JobExecutableCustomerIDに関連付けられたJobExecutableCustomerExecutionLog.JobExecutionLogIDが実際に(関係を上に向かって)確認できるようにしたい「テキストメッセージの送信」ではなく「メールの送信」のJob.IDに属しています。

それを見ると、2つのオプションがあります:

  1. 値をJob.IDからすべての子テーブルにプッシュし、Foreign Keyの一部にします
  2. 別のプロセス(TriggerまたはIndexed View)で関係を確認してください

個人的には、他のすべての子テーブルでJob.ID値をプッシュするのが好きではないので、Triggerなどを使用してそれを処理することに傾倒しています。それらが私の2つの唯一のオプションであるのか、それとも「通常の」Foreign Keyを設定して関係を完全にトラバースする機能があるのか​​、私にはわかりませんでした。ある種のCascadeか何かで。

3
Kirk Saunders

個人的には、他のすべての子テーブルにJob.ID値をプッシュするという考えは好きではありません。

何故なの?明白な解決策は、JobIDをすべての子テーブルの主要なPK /クラスター化インデックス列にすることです。そして、JobIDによってこれらすべてのテーブルにアクセスするための最適なパフォーマンスを保証します。

通常、「識別関係」または「子テーブル」または「弱いエンティティ」がある場合は常に、子テーブルは、主列が親テーブルへの外部キーでもある複合主キーを使用する必要があります。このようなもの:

create table Parent
(
  ParentId int not null identity,
  constraint pk_Parent
    primary key(ParentId)
)

create table Child
(
  ParentId int not null, 
  ChildId int not null identity, 
  constraint pk_Child 
    primary key (ParentId,ChildId),
  constraint fk_Child_Parent
    foreign key (ParentId) references Parent(ParentId)
    on delete cascade
)
create table GrandChild
(
  ParentId int not null references Parent, 
  ChildId int not null, 
  GrandChildId int not null identity,
  constraint pk_GrandChild 
    primary key (ParentId,ChildId,GrandChildId),
  constraint fk_GrandChild_Child
    foreign key (ParentId) references Parent(ParentId)
    on delete cascade
)