テーブル設計の経験はあまりありません。私の目標は、以下の要件を満たす 1 つ以上の製品テーブルを作成することです。
多くの種類の製品 (テレビ、電話、PC など) をサポートします。製品の種類ごとに、次のような異なるパラメータ セットがあります。
電話には色、サイズ、重量、OS...
PCにはCPU、HDD、RAM...
パラメータのセットは動的でなければなりません。任意のパラメータを追加または編集できます。
製品の種類ごとに個別の表を作成せずに、これらの要件を満たすにはどうすればよいですか?
テーブル設計の経験はあまりありません。私の目標は、以下の要件を満たす 1 つ以上の製品テーブルを作成することです。
多くの種類の製品 (テレビ、電話、PC など) をサポートします。製品の種類ごとに、次のような異なるパラメータ セットがあります。
電話には色、サイズ、重量、OS...
PCにはCPU、HDD、RAM...
パラメータのセットは動的でなければなりません。任意のパラメータを追加または編集できます。
製品の種類ごとに個別の表を作成せずに、これらの要件を満たすにはどうすればよいですか?
記述した型階層をモデル化するには、少なくとも次の 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)。JOIN複数の行から属性を取得するには、属性ごとに行う必要があるため、従来の表形式のレイアウトで結果を取得するのは複雑で費用がかかります。EAV が提供する柔軟性の程度には、他の領域での犠牲が必要であり、おそらくコードは、より従来の方法で元の問題を解決する場合よりも複雑 (または悪化) になります。
ほとんどの場合、その程度の柔軟性は必要ありません。製品タイプに関するOPの質問では、製品固有の属性の製品タイプごとにテーブルを作成する方がはるかに簡単なので、少なくとも同じ製品タイプのエントリに対して一貫した構造が適用されます.
すべての行が個別の属性セットを持つ可能性を許可する必要がある場合にのみ、EAV を使用します。製品タイプのセットが限られている場合、EAV はやり過ぎです。クラステーブルの継承が私の最初の選択肢です。
2019 年の更新: 「多くのカスタム属性」の問題の解決策として JSON を使用している人を見るほど、その解決策は好きではなくなります。特別なJSON 関数を使用してサポートしている場合でも、クエリが複雑になりすぎます。JSON ドキュメントを保存するには、通常の行と列に保存する場合と比べて、より多くのストレージ スペースが必要です。
基本的に、これらのソリューションはいずれも、リレーショナル データベースでは簡単でも効率的でもありません。「可変属性」を持つという考え全体は、基本的にリレーショナル理論と矛盾しています。
つまり、アプリにとって最も悪影響が少ないものに基づいて、ソリューションの 1 つを選択する必要があります。したがって、データベースの設計を選択する前に、データをクエリする方法を知る必要があります。どのソリューションも特定のアプリケーションに最適である可能性があるため、"最適な" ソリューションを 1 つ選択する方法はありません。
@石の心
ここでは、EAV と MVC をずっと使用します。
@ビル・カービン
EAV の欠点のいくつかを次に示します。
- 列を必須にする方法はありません (NOT NULL と同等)。
- エントリを検証するために SQL データ型を使用する方法はありません。
- 属性名のスペルが一貫していることを保証する方法はありません。
- ルックアップテーブルなど、特定の属性の値に外部キーを配置する方法はありません。
ここで言及したすべてのこと:
私の意見では、アプリケーションのプログラミング言語のように適切なレベルでこれらの相互作用や要件を処理できるデータベースはないため、データベースにはまったく属しません。
私の意見では、データベースをこのように使用することは、石を使って釘を打つようなものです。岩でもできますが、この種の活動のために特別に設計されたより正確なハンマーを使用することを想定していませんか?
複数の行から属性を取得するには、属性ごとに JOIN を実行する必要があるため、従来の表形式のレイアウトで結果を取得するのは複雑で費用がかかります。
この問題は、部分的なデータに対していくつかのクエリを作成し、それらをアプリケーションで表形式のレイアウトに処理することで解決できます。600 GB の製品データがある場合でも、このテーブルのすべての行からデータが必要な場合は、バッチで処理できます。
さらにクエリのパフォーマンスを向上させたい場合は、レポートやグローバル テキスト検索などの特定の操作を選択し、必要なデータを格納し、定期的に (たとえば 30 分ごとに) 再生成されるインデックス テーブルを準備できます。
追加のデータ ストレージのコストを気にする必要さえありません。
アプリケーションによって実行される操作のパフォーマンスにまだ関心がある場合は、いつでも Erlang、C++、Go 言語を使用してデータを前処理し、後でメイン アプリで最適化されたデータをさらに処理することができます。
Class Table Inheritance意味を使用する場合:
すべての製品タイプに共通の属性を格納する、製品用の 1 つのテーブル。次に、製品タイプごとに 1 つのテーブルで、その製品タイプに固有の属性を格納します。-ビル・カーウィン
Bill Karwin's Suggestions の中で私が最も気に入っているのはどれですか.. 1 つの欠点を予測することができます。それが問題にならないようにする方法を説明しようと思います。
ある属性が 1 つのタイプにのみ共通で、次に 2、3 などに共通になった場合、どのような緊急時対応計画を立てる必要がありますか?
例:(これは単なる例であり、実際の問題ではありません)
家具を販売する場合、椅子、ランプ、ソファ、テレビなどを販売する場合があります。テレビの種類は、電力を消費する唯一の種類である可能性があります。したがって、power_consumption属性を に配置しますtv_type_table。しかしその後、特性を持つホーム シアター システムの取り扱いを開始しましたpower_consumption。他の製品は 1 つだけなので、このフィールドを にも追加しますstereo_type_table。しかし、時間が経つにつれて、ますます多くの電子機器を持ち始めるようになり、power_consumptionそれがmain_product_table. 私は今どうすればいい?
にフィールドを追加しますmain_product_table。type_table電子機器をループして、それぞれから正しい値を に入れるスクリプトを作成しますmain_product_table。次に、各 からその列をドロップしますtype_table。
ここで、常に同じGetProductDataクラスを使用してデータベースと対話し、製品情報を取得していたとします。コードの変更でリファクタリングが必要になった場合は、そのクラスのみに変更する必要があります。
Productテーブルと、製品ID、追加情報名、追加情報値の3つの列を持つ個別のProductAdditionInfoテーブルを作成できます。すべてではありませんが多くの種類の製品で色が使用されている場合は、それをProductテーブルのnull許容列にするか、ProductAdditionalInfoに配置することができます。
このアプローチは、リレーショナルデータベースの従来の手法ではありませんが、実際に多く使用されているのを見てきました。柔軟性があり、優れたパフォーマンスを発揮します。
Steve Yeggeはこれをプロパティパターンと呼び、その使用について長い投稿を書きました。