これらのうち、真に正規化された設計である (またはいずれでもない) のはどれですか?
それらはすべて「正規化」されていますが、すべてが同じように役立つわけではありません。
1) 空っぽをたくさん残すと、きれいに成長しません。
NULL は、ほとんどの DBMS でかなり効率的に格納されます。通常は 1 バイト、または理想的な環境下の一部の DBMS ではわずか 1 ビットです。
CHECK を使用して、そのうちの 1 つだけが非 NULL であることを確認できます。
2) 外部キー制約を強制するにはどうすればよいですか?
理論的には、FK を下に移行joins_with_tableしてから、参照テーブルに CHECK を設定して、適切な型を確保することができます。明らかに、これは扱いにくく、スペースを浪費します (DBMS が計算列/仮想列をサポートしていない場合)。
トリガーまたは (絶対に禁じられている) アプリケーション ロジックに依存することもできますが、単純さ、堅牢性、および速度のために、可能な限り宣言型の制約を優先する必要があります。
乾燥していないので、すぐに 3 を除外します。
残念ながら、リレーショナル データベースは多くの場合、OO プログラミングで慣れ親しんだ概念をサポートしていないため、結果として不必要な繰り返しが発生する可能性があります。たとえば、テーブルの継承 (ベース テーブルが「構造」を定義し、子が特定の FK を定義する) は、この場合の繰り返しを軽減するのに理想的です。
現状では、バランスを崩さない限り、いくつかの繰り返しは世界で最悪のことではありません.
簡潔に参加するにはどうすればよいですか?
あなたの質問がよくわかりません。明確にしてください。必要に応じて、JOIN は、テーブルのデザインだけでなく、キーのデザインによっても大きく影響を受ける可能性があります。
全体として、(3) を正当化する可能性のある他の違いが予想されない限り、私はおそらく (1) を使用します。