次のER図があるとします。
School
でStudent
の外部キーを使用して関係を表した場合、NULL
値を持つことができます(Student
は所属する必要がないためSchool
)、たとえば:
したがって、正しい方法は(私が読んだ内容に基づいて)、関係を表す交差テーブルを作成することです。次に例を示します。
このように、NULL
値はテーブルSchool_has_Student
に存在できません。
しかし、交差テーブルを作成する代わりにnull可能な外部キーを使用することの欠点は何ですか?
編集:
(school_id
、student_id
)をSchool_has_Student
テーブルの主キーとして誤って選択したため、リレーションシップは多対多になりました。正しい主キーはstudent_id
である必要があります:
2つのモデルは異なる関係を表しています。
結合テーブルを使用すると、多対多の関係をモデル化できます。
単純な外部キーを使用して、1対多の関係をモデル化します。
Null可能な外部キーの短所は、多対多の関係をモデル化できないことです(それが目的の場合)。
質問に対する編集に基づいて、生徒のテーブルを同じキーを持つ2つのテーブルに効果的に分割しています。私は通常、フィールドが多すぎるテーブルでこれを確認します。そのため、管理しやすくするために誰かがそれらを2つに分割します(私は豚に口紅を置くと言います)。
Studentテーブルを分割すると、2番目のテーブルにレコードが存在する必要がないため、2番目のテーブルがオプションになります。これは、nullになる可能性があるため、設定する必要がないフィールドとよく似ています。
1対多の関係が必要な場合は、単一のテーブルを使用して、生徒のテーブルで学校IDをnullにすることをお勧めします。外部キーであっても、フィールドでnullを回避する理由はありません。これは、外部関係がオプションであることを示しています。開発者とDBAはそれを明確に理解しており、基盤となるデータベースエンジンは確実に機能するはずです。
結合について心配する場合は、心配しないでください。結合がnullフィールドでどのように機能するかについては、明確なセマンティクスがあります。単一のテーブルを使用すると、3つではなく2つのテーブルを結合できます。
あなたは上のコメントに書きました:
"Fundamentals of Database Systems" [...]は、外部キー列に多くのNULL値がある場合は交差テーブルを使用することをお勧めします(例:従業員の98%の場合)部門を管理しないでください)
外部キー列に多くのNULL値がある場合、プログラムは、処理するすべてのレコードについて、このほとんど空の列を処理する必要があります。すべてのケースの98%が空であるにもかかわらず、列はおそらくディスク領域を占有します。関係のクエリは、より多くのネットワークトラフィックを提供するその列をクエリすることを意味し、テーブルからクラスを生成するORMを使用している場合、プログラムまた、クライアント側に必要以上のスペースが必要になります。交差テーブルを使用すると、これが回避され、同等の外部キーがNULLにならない場合にのみリンクレコードが必要になります。
反対に、いくつかのNULL値がない場合、50%以上のリレーションがNULLでないとしましょう。交差テーブルを使用すると、反対の効果が得られます-ディスク容量が増え、複雑さが増し、ネットワークトラフィックが増加します。
したがって、交差テーブルの使用は、最適化の一形態にすぎず、特定の場合にのみ有効であり、特に最近では、ディスクスペースとメモリが安価になり、必要な頻度がはるかに少なくなりました。 「Fundamentals of Database Systems」はもともと20年以上前に書かれたものであり(1994年の第2版への言及を見つけました)、その時点ですでに推奨はあったと思います。 1994年までは、マスストレージはさらに高価であり、コンピューターとネットワークは今日よりもはるかに遅いため、スペースの最適化はおそらく今日よりもはるかに重要でした。
うるさいコメントの補足として:上記のステートメントは、 "Fundamentals of Database Systems"の作者が彼の推奨事項を念頭に置いたものを予想することを試みているだけで、大まかな一般的なステートメントを有効にしていたと思いますほとんどのシステムでは、一部のデータベースでは、「疎列」のような他の可能な最適化があり、交差テーブルの使用がさらに廃止されています。
ですから、その推奨事項を誤解しないでください。この本は、一般的に{0,1}:n
関係の交差テーブルを優先するように、またはあなたが書いたように、これが「正しい方法」であることを教えていません。このような最適化を使用すると、本当に必要な場合にのみプログラムが複雑になります。
概念モデルは次のようになります。これは、控えめに言っても非常に非正統的なです。
物理モデルは次のようになります。これは混乱を招く少ない(つまり、人々はよく見ていない限り、M:Mであると考えます)。
私の提案:
多くの列(FKまたはその他)があり、ほとんどの学生には当てはまらない場合は、テーブルを1:1 relのロールテーブルに分けます。しかし、それはFKであるからではなく、列がほとんどの行に適用されないためです。
それ以外の場合、nullable FKはデータベースの通常の部分であり、結合テーブルは通常M:M rels用です。
1:1 relの一般的な用途は、エンティティが特定のタイプの場合にのみ適用される列を持ち、パフォーマンスまたはストレージを考慮してBLOB列を抽出するロールテーブルの場合です。 FKでnull値を回避することは、その一般的な使用法の1つではありません。
他の回答に加えて、外部キーのnull値があいまいであることを指摘したいと思います。それは意味しますか:
1)学生の学校(ある場合)は不明です(これは「null」の標準的な意味です-値は不明です)
2)生徒が学校を持っているかどうかがわかっていて、学校がない
Nullの標準的な意味を使用する場合、外部キーモデルで「学生には学校がない」をどのように表すでしょうか。その場合は、おそらく学校のテーブルに独自のIDを持つ「学校なし」のエントリを作成する必要があります。 (理想的ではない)
データベーステーブルには、制約と呼ばれるこの素晴らしい機能があります。したがって、交差表で作成するのは非常に簡単で、テーブルに表示されるのは各学生の1人だけですが、そのテーブルには多くの学校があります。効果的にあなたに与える
理論はいいですが、最終的には、質問した後にデータベースをモデル化します。
「どの生徒が私の学校にいるのか」という質問を頻繁に行う場合は、実際に生徒テーブル全体を照会するのか、それとも簡単な交差テーブルを作成するのかを考えます。
データベース:質問に合わせて最適化します。
3番目のテーブルを使用することが実際に意味のあるユースケースがあります。例は純粋に仮説のように思われるかもしれませんが、私はそれが私のポイントをよく説明していると思います。 students
テーブルにさらに列を追加し、ある時点で、いくつかの列の複合インデックスを介してレコードに一意性を適用するとします。 school_id
列も含める必要がある可能性が非常に高く、ここで問題が発生し始めます。 SQLの設計方法により、school_id
がNULL
である同じレコードをいくつか挿入することが可能になります。技術的な観点からは完全に理にかなっていますが、直感に反しており、予期しない結果が生じる可能性があります。一方、交差点テーブルに一意性を適用するのは簡単です。
最近、そのような「オプション」の関係をモデル化する必要がありました。一意性制約の要件は、タイムスタンプ列によるものでした。テーブルにnull可能な外部キーを残すと、同じタイムスタンプのレコードが挿入される可能性があります(これはデフォルトのレコードであり、まだ監査/承認されていないレコードに設定されていると仮定します)。 null可能な列。
ご覧のとおり、それはかなり特殊なケースであり、他の人が指摘しているように、ほとんどの場合、すべてのNULL
値で完全に問題ありません。それは実際にはモデルの特定の要件に依存します。
すでに提出された多くの良い提案に加えて、個人的に私は、本当に必要な場合を除いて、外部キーのファンではありません。まず、参照しているM:M関係があります。さらに、外部キーを呼び出し、それによってそのテーブルデータをクエリに取り込むと、複雑さが増し、テーブルサイズによってはパフォーマンスが低下します。他の人が言ったように、null可能FKフィールドはサポートされない可能性があり、データの整合性の問題を引き起こす可能性があります。
生徒の学校が不明または空の状態を定義している場合、NULLはそれらの条件を区別しません。 (ここでもデータの整合性に戻ります。)Tulainsによるロールテーブルの提案は洗練されており、null値を適切に許可します。