記述した型階層をモデル化するには、少なくとも次の 5 つのオプションがあります。
単一テーブルの継承: すべてのタイプのすべての属性を格納するのに十分な列を備えた、すべての製品タイプの 1 つのテーブル。これは、多くの列を意味し、そのほとんどは特定の行で NULL です。
Class Table Inheritance : Products の 1 つのテーブルで、すべての製品タイプに共通の属性を格納します。次に、製品タイプごとに 1 つのテーブルで、その製品タイプに固有の属性を格納します。
具体的なテーブルの継承: 共通の製品属性のテーブルはありません。代わりに、製品タイプごとに 1 つのテーブルがあり、共通の製品属性と製品固有の属性の両方が格納されます。
シリアル化された LOB : 製品の 1 つのテーブルで、すべての製品タイプに共通の属性が格納されます。追加の 1 つの列には、半構造化データの BLOB が XML、YAML、JSON、またはその他の形式で格納されます。この BLOB を使用すると、各製品タイプに固有の属性を格納できます。Facade や Memento などのファンシーなデザイン パターンを使用して、これを説明できます。しかし、SQL 内で簡単に照会できない属性の塊があるにもかかわらず。ブロブ全体をアプリケーションに戻して、そこでソートする必要があります。
Entity-Attribute-Value : 製品用の 1 つのテーブルと、属性を列ではなく行にピボットする 1 つのテーブル。EAV は、リレーショナル パラダイムに関して有効な設計ではありませんが、とにかく多くの人が使用しています。これは、別の回答で言及されている「プロパティパターン」です。いくつかの落とし穴については、StackOverflowのeav タグで他の質問を参照してください。
これについては、 Extensible Data Modelingというプレゼンテーションで詳しく説明しています。
EAV についての追加の考え: 多くの人が EAV を好むようですが、私はそうではありません。これは、最も柔軟なソリューションのように思われるため、最適です。ただし、 TANSTAAFLという格言を覚えておいてください。EAV の欠点のいくつかを次に示します。
- 列を必須にする方法はありません ( と同等
NOT NULL
)。
- エントリを検証するために SQL データ型を使用する方法はありません。
- 属性名のスペルが一貫していることを保証する方法はありません。
- ルックアップテーブルなど、特定の属性の値に外部キーを配置する方法はありません。
JOIN
複数の行から属性を取得するには、属性ごとに行う必要があるため、従来の表形式のレイアウトで結果を取得するのは複雑で費用がかかります。
EAV が提供する柔軟性の程度には、他の領域での犠牲が必要であり、おそらくコードは、より従来の方法で元の問題を解決する場合よりも複雑 (または悪化) になります。
ほとんどの場合、その程度の柔軟性は必要ありません。製品タイプに関するOPの質問では、製品固有の属性の製品タイプごとにテーブルを作成する方がはるかに簡単なので、少なくとも同じ製品タイプのエントリに対して一貫した構造が適用されます.
すべての行が個別の属性セットを持つ可能性を許可する必要がある場合にのみ、EAV を使用します。製品タイプのセットが限られている場合、EAV はやり過ぎです。クラステーブルの継承が私の最初の選択肢です。
2019 年の更新: 「多くのカスタム属性」の問題の解決策として JSON を使用している人を見るほど、その解決策は好きではなくなります。特別なJSON 関数を使用してサポートしている場合でも、クエリが複雑になりすぎます。JSON ドキュメントを保存するには、通常の行と列に保存する場合と比べて、より多くのストレージ スペースが必要です。
基本的に、これらのソリューションはいずれも、リレーショナル データベースでは簡単でも効率的でもありません。「可変属性」を持つという考え全体は、基本的にリレーショナル理論と矛盾しています。
つまり、アプリにとって最も悪影響が少ないものに基づいて、ソリューションの 1 つを選択する必要があります。したがって、データベースの設計を選択する前に、データをクエリする方法を知る必要があります。どのソリューションも特定のアプリケーションに最適である可能性があるため、"最適な" ソリューションを 1 つ選択する方法はありません。