4

リレーショナル トポロジを格納する次の方法を実装しました。

1.一般接合関係表:

表: 関係

列: id 親の型 親の ID 親のプロップ 子の型の子 ID 子供のプロップ

一般に、ほとんどの SQL エンジンで実行できない結合。

2.リレーション固有のジャンクション テーブル

表: Class2Student

列: id parent_id parent_prop child_id child_prop

どのジョインに対して実行できるか。

text3.両方の双方向オブジェクトのフィールドに、関連するオブジェクトのリスト/文字列マップを格納します。

クラス: クラス

クラス プロパティ: ID 名前 学生

テーブルの列: ID 名 students_keys

行: 1 "履歴" [{type:Basic_student,id:1},{type:Advanced_student,id:3}]

[1,3]SQL エンジンによる結合を有効にするために、students_keys の内容が単純である場合、つまりリレーションが明示的な型である場合はさらに簡単になるカスタム モジュールを作成することができますStudent

質問は、次のコンテキストで次のとおりです。

ジャンクション テーブルの要点がわかりません。たとえば、ジャンクション テーブルの次の引数が緩和すると主張する問題が実際に存在することを確認できません。

  • 双方向のリレーションを論理的に正しく保存できない (たとえば、双方向のリレーションやkeysフィールドとのリレーションにデータの孤立はありません。これは、再帰的に保存し、他の操作 (削除、更新) を非常に簡単に実行できるためです)
  • 効果的に参加できない

私は、ベスト プラクティスに関するあなたの個人的な意見や、正規化に関するカルトのような声明に対する意見を求めているわけではありません。

明確な質問は次のとおりです。

  1. keys所有しているオブジェクトのフィールドを照会することによって提供されないジャンクション テーブルを照会したい場合は、どのような場合ですか?
  2. ジャンクションテーブルが望ましいSQLエンジンによって提供される計算のコンテキストにおける論理的な実装の問題は何ですか?
  3. junction tablea フィールドとaフィールドに関する唯一の実装の違いkeysは次のとおりです。

keys次の性質のクエリを検索する場合は、カスタム インデックス実装またはその他の適切な実装のいずれかを使用して、フィールドと照合する必要があります。

class_dao.search({生徒:上級_生徒_3,名前:"履歴"});

特定の生徒と名前「history」を持つクラスを検索します

ジャンクション テーブルのインデックス付きの列を検索してから、適切なクラスを選択するのとは対照的です。

文字通り何らかの理由でジャンクションテーブルが論理的に好ましい理由を特定できませんでした。私はこれが事実であると主張しているわけではありません。また、これを達成するために複数の方法を実装したという事実によって証明されるように、何らかの形で宗教的な好みがあると主張しているわけでもありません。私の問題は、それらが何であるかわからないことです。

4

1 に答える 1

2

私の見方では、あなたにはいくつかのエンティティがあります

CREATE TABLE StudentType
(
    Id Int PRIMARY KEY,
    Name NVarChar(50) 
);

INSERT StudentType VALUES
(
    (1, 'Basic'),
    (2, 'Advanced'),
    (3, 'SomeOtherCategory')
);

CREATE TABLE Student
(
    Id Int PRIMARY KEY,
    Name NVarChar(200),
    OtherAttributeCommonToAllStudents Int,
    Type Int,
    CONSTRAINT FK_Student_StudentType
        FOREIGN KEY (Type) REFERENCES StudentType(Id)
)

CREATE TABLE StudentAdvanced
(
    Id Int PRIMARY KEY,
    AdvancedOnlyAttribute Int,
    CONSTRIANT FK_StudentAdvanced_Student
        FOREIGN KEY (Id) REFERENCES Student(Id)
)

CREATE TABLE StudentSomeOtherCategory
(
    Id Int PRIMARY KEY,
    SomeOtherCategoryOnlyAttribute Int,
    CONSTRIANT FK_StudentSomeOtherCategory_Student
        FOREIGN KEY (Id) REFERENCES Student(Id)
)
  1. すべての学生に共通する属性には、Student表に列があります。
  2. 余分な属性を持つ学生のタイプがStudentTypeテーブルに追加されます。
  3. 追加の各学生タイプは、Student<TypeName>特定の属性を格納するためのテーブルを取得します。これらのテーブルには、オプションで との 1 対 1 の関係がありStudentます。

あなたの「ストローマン」ジャンクションテーブルはEAVアンチパターンの部分的な実装であると思います。これが賢明なのは、モデル化する必要がある属性がわからない場合、つまりデータが完全に構造化されていない場合だけです。 . これが実際の要件である場合、リレーショナル データベースはあまり望ましくないように見え始めます。そのような場合は、NOSQL/ドキュメント データベースの代替手段を検討してください。


ジャンクション テーブルは、次のシナリオで役立ちます。

クラス エンティティをモデルに追加するとします。

CREATE TABLE Class
(
    Id Int PRIMARY KEY,
    ...
)

学生とクラスの間の多対多の関係を保存したいと考えています。

CREATE TABLE Registration
(
    Id Int PRIMARY KEY,
    StudentId Int,
    ClassId Int,
    CONSTRAINT FK_Registration_Student
        FOREIGN KEY (StudentId) REFERENCES Student(Id),
    CONSTRAINT FK_Registration_Class
        FOREIGN KEY (ClassId) REFERENCES Class(Id)
)

このエンティティは、学生のクラスへの登録に特に関連する属性 (たとえば、完了フラグなど) を格納するのに適した場所です。他のデータは、おそらくクラス固有の出席記録や成績履歴など、当然このジャンクションに関連します。

Classこのように関連付けない場合Student、クラスのすべての生徒と生徒が読むすべてのクラスの両方をどのように選択しますか。パフォーマンスに関しては、これはキー列のインデックスによって簡単に最適化されます。


多対多の関係が属性なしで存在する場合、論理的にはジャンクション テーブルが存在する必要がないことに同意します。ただし、リレーショナル データベースでは、ジャンクション テーブルは依然として有用な物理実装です。おそらく次のようになります。

CREATE TABLE StudentClass
(
    StudentId Int,
    ClassId Int,
    CONSTRAINT PK_StudentClass PRIMARY KEY (ClassId, StudentId),
    CONSTRAINT FK_Registration_Student
        FOREIGN KEY (StudentId) REFERENCES Student(Id),
    CONSTRAINT FK_Registration_Class
        FOREIGN KEY (ClassId) REFERENCES Class(Id)
)

これにより、次のような単純なクエリが可能になります

// students in a class?
SELECT StudentId
FROM StudentClass
WHERE ClassId = @classId

// classes read by a student?
SELECT ClassId
FROM StudentClass
WHERE StudentId = @studentId

さらに、これにより、リレーショナル データベース開発者になじみがあり、クエリ オプティマイザがサージ可能な、いずれかの側面から部分的または完全に関係を管理する簡単な方法が可能になります。

于 2014-03-13T09:54:20.707 に答える