2016-12-05 2 views
1

私は1対多の関係のためのSQLデータベーススキーマのための最良のデザインを見つけることを試みています。私のプロジェクトでは、私はnodesの番号で構成されたobjectsを持っていて、それぞれにroot_nodeというオプションの外部キーの参照があるようにしたいと思います。お互いに逆参照を使って1対多の関係に最適なデザインは何ですか?

-- schema A 

CREATE TABLE objects (
    object_id integer NOT NULL PRIMARY KEY, 
    root_node integer REFERENCES nodes(node_id), 
    <some other data> 
); 

CREATE TABLE nodes (
    node_id integer NOT NULL PRIMARY KEY, 
    object_id integer REFERENCES objects, 
    <some other data> 
); 

は、しかし、今、私たちは、私は良いことであることを確認していない互いへの外​​部キー参照を持つ2つのテーブルがありますので、私の最初のソリューションは、この(わかりやすくするために、私は依存関係の問題をスキップしています)のように見えます。

-- schema B 

CREATE TABLE objects (
    object_id integer NOT NULL PRIMARY KEY, 
    <some other data> 
); 

CREATE TABLE root_nodes (
    object_id integer REFERENCES objects PRIMARY KEY, 
    root_node integer REFERENCES nodes(node_id), 
); 

CREATE TABLE nodes (
    node_id integer NOT NULL PRIMARY KEY, 
    object_id integer REFERENCES objects, 
    <some other data> 
); 

だから私の質問は次のとおりです:両方ABデザインは許容可能であると考えるか、または知られている「最高のがあるので、私は代わりにobjectsテーブル内root_nodeを置くこと、それがroot_nodesとして個別に格納されている場合、別のアプローチを検討していますもう一つ上のものを好むでしょうか?もしそうなら、スキーマの方が優れている理由を説明してください。

+0

@AntonínLejsek - はい、ありがとうございます!修正されました。 – Yatima

答えて

0

スキーマBオブジェクトには複数のルートノードがあり、ルートノードは別のオブジェクトのノードになります。スキーマAはオブジェクトのルートノードを1つだけ強制します(これは私が推測したいものです)が、2番目の問題を共有します。このための「ベストプラクティス」があるかどうかはわかりませんが、ここにいくつかのアイデアがあります。

あなたがオブジェクトのためのより多くのルートノードが必要な場合は、それを行うには実際には非常に簡単です、あなただけのビットフラグが必要です。

CREATE TABLE objects (
    object_id integer NOT NULL PRIMARY KEY, 
    <some other data> 
); 

CREATE TABLE nodes (
    node_id integer NOT NULL PRIMARY KEY, 
    object_id integer REFERENCES objects, 
    is_root bit NOT NULL 
    <some other data> 
); 

をあなたがオブジェクトのための唯一の1つのルートノードが必要な場合は、フィルタ追加できますユニークインデックス:

CREATE UNIQUE NONCLUSTERED INDEX unique_root_for_object ON nodes 
(
    object_id 
) 
WHERE (is_root = 1) 

今はスキーマCとします。今度は、スキーマAに戻り、「別のオブジェクトからのルート」問題を修正します。あなたは、ルートノードが対象ノードの一つで強制的に複合外部キーを追加することができます。これが動作するためにあなたは、テーブルノード上(OBJECT_ID、NODE_ID)に一意索引が必要になります

ALTER TABLE objects WITH CHECK CHECK 
CONSTRAINT FK_objects_nodes FOREIGN KEY(object_id, root_node) 
REFERENCES nodes (object_id, node_id) 

。もちろんルートノードのないオブジェクトを持つことはできますが、この外部キーに違反しません。

スキーマAまたはCが優れていますか?スキーマCはより柔軟に見えます。たとえば、ルートノードとしてノードを1つの挿入物に追加することができます。また、複数のルートノードに簡単に切り替えることもできます。一方、スキーマAでは、ルートノード情報を持つオブジェクトにインデックスを作成することができます。変更を記録すると、ノードの変更ではなく、オブジェクトの変更としてルートノードの変更が記録されます。依存関係がより明示的になります。これは、一部のクエリを単純化し、ORMもクエリを簡略化します。

これを行う別の方法があります。大まかには、設計上データの不一致を許さないスキーマに固執しようとします。

+0

reスキーマBオブジェクトに複数のルートノードを持つことができ、ルートノードは別のオブジェクトのノードになることがあります。私はroot_nodesテーブルを変更したので、PRIMARY KEYが存在するので、オブジェクト発行のために複数のルートノードを解決する必要があります。そして私は、 'A 'から同様の' CHECK CONSTRAINT'を導入する方法があると推測していますので、単一のノードは複数のオブジェクトで 'root_node'になることはできませんでしたか?スキーマBの問題に対処すると思いますか?スキームCへの私の主な反論は余分な「ビット」です。それは無駄だと思われます。 – Yatima

+0

スキーマBはスキーマAと同様ですが、オブジェクトは2つのテーブルに分割されています。リレーショナルデータベースでISAオブジェクトの関係をモデル化するとき、私はそのようなことを見ることができます。私はここで多くの利点を見ていないと私の経験からそれを避けるためにしようとします。 "厄介なビット"は私には奇妙に思える、それはテーブルのシンプルなインデックスのサイズの1%のような、私にとってかなり効率的だね。しかし、選択肢はあなた次第です。単一のルートノードのシナリオでは私は個人的にスキーマAの方法を好みます。 –

+0

私は参照してください。したがって、両方とも外部キー参照を持つ2つのテーブル(オブジェクト、ノード)の問題を予見しませんか? – Yatima

0

このシナリオでは、テーブル定義が与えられていることをDBに認識させないように、データに追加の制約を適用しています。
制約を適用するためのトリガを追加する必要があります。または、ルート以外の情報を完全に除外し、必要に応じてプログラムで検索します。

現在のスキームの最大の問題は、一方のテーブル内の情報を変更して他方の情報を意味的に間違ってしまうことです。

例:

A -> B -> C 
A is the root node of C 

私は1つのテーブルで何かを更新したが、他にそうするように無視して、あなたのいずれかの形式でこれを破ることができます。私はCのルートノードをBに更新できますが、AとBの間の親子関係を削除することを忘れてしまいます。あるいは、Aに親を追加して、BまたはCのルートノード情報を更新することを忘れてしまいます。

My提案は、ルートノードのデータを格納せず、必要なときに計算することです。

+0

私の質問の一部はわかりにくいものでしたが、これは木のような構造を格納する方法ではなく、お互いに外部キー参照を持つ2つのテーブルを持つか、より良い方法がある場合はOKです。また、この特定のプロジェクトでは、すべての 'nodes'は等価であり、必ずしもネストされていないので、ルートノードを計算することは不可能です。 – Yatima

+0

また、あるテーブルのレコードを更新し、他のテーブルのレコードを更新することを忘れている可能性についての良い点: - これを軽減し、全体的な意図を明確にするために、主キーを編集してroot_nodesテーブルに追加しました。 – Yatima

関連する問題