各製品に多くのパラメーターがある多くの種類の製品の製品テーブルを設計する方法


140

私はテーブルデザインの経験があまりありません。私の目標は、以下の要件を満たす1つ以上の製品テーブルを作成することです。

  • 多くの種類の製品(TV、電話、PCなど)をサポートします。製品の種類ごとに、次のような異なるパラメータセットがあります。

    • 電話には、色、サイズ、重量、OSがあります...

    • PCにはCPU、HDD、RAMが搭載されています...

  • パラメータのセットは動的である必要があります。任意のパラメーターを追加または編集できます。

製品の種類ごとに個別の表がなくても、これらの要件を満たすにはどうすればよいですか?

回答:


233

記述するタイプ階層をモデル化するには、少なくとも次の5つのオプションがあります。

  • 単一のテーブル継承:すべての製品タイプの1つのテーブル。すべてのタイプのすべての属性を格納するのに十分な列があります。これは、多くの列を意味、そのほとんどは特定の行でNULLです。

  • クラステーブル継承:すべての製品タイプに共通の属性を格納する、製品の1つのテーブル。次に、製品タイプごとに1つのテーブルに、その製品タイプに固有の属性を格納します。

  • 具体的なテーブル継承:一般的な製品属性のテーブルはありません。代わりに、製品タイプごとに1つのテーブルがあり、共通の製品属性と製品固有の属性の両方が格納されています。

  • シリアル化されたLOB:すべての製品タイプに共通の属性を格納する製品用の1つのテーブル。1つの追加の列には、XML、YAML、JSON、またはその他の形式で、半構造化データのBLOBが格納されます。このBLOBを使用すると、各製品タイプに固有の属性を格納できます。FacadeやMementoなどのデザインパターンを使用してこれを説明できます。ただし、SQL内で簡単にクエリできない属性のblobがある場合でも、ブロブ全体をフェッチしてアプリケーションに戻し、そこで整理する必要があります。

  • 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つ選択する方法はありません。


11
@HimalayaGargオプション「4.5」は、Billの投稿の全体の要点とは正反対です。
user3308043 14

2
MySQLとは異なり、SQL ServerはXML、XPath、XQueryを幅広くサポートしています。したがって、SQL Serverのユーザーにとって、最良のオプションは、XMLタイプの列に追加の属性を格納することです(オプション4)。このようにして、「BLOB全体をアプリケーションにフェッチし、そこで整理する」必要はありません。SQL Serverでは、XML列にインデックスを作成することもできます。
Delphi.Boy


2
私の場合は、シリアル化されたLOBを好みます。しかし、それはORMに適していますか?私はEFを使用しています。
Mahmood Jenami 2015年

@ user2741577確かに、しかし、おそらく構造化されていないデータのフィールドをLOBからアンパックし、それらをORMオブジェクトの各エンティティフィールドに適用するカスタムコードを記述する必要があります。EFはわかりませんが、これを行う基本ORMクラスを作成できると思います。オブジェクトを保存するときにLOBを再作成できるように、データベース行の具体的なフィールドからのフィールドとLOBのフィールドからのフィールドを追跡する必要があります。
ビルカーウィン2015年

12

@石の心

私はここまでずっとEAVとMVCで行きます。

@ビル・カービン

EAVの欠点のいくつかを次に示します。

  • 列を必須にする方法はありません(NOT NULLと同等)。
  • SQLデータ型を使用してエントリを検証する方法はありません。
  • 属性名のスペルが一貫していることを確認する方法はありません。
  • たとえばルックアップテーブルの場合など、特定の属性の値に外部キーを配置する方法はありません。

ここで言及したすべてのこと:

  • データ検証
  • 属性名のスペル検証
  • 必須の列/フィールド
  • 依存属性の破棄の処理

私の意見では、データベースはアプリケーションのプログラミング言語のように適切なレベルでこれらの相互作用と要件を処理することができないため、データベースにはまったく属していません。

私の意見では、データベースをこのように使用することは、岩を使って釘を打ち込むようなものです。あなたは岩を使ってそれを行うことができますが、この種の活動のためにより正確で特別に設計されたハンマーを使用することを想定していませんか?

複数の行から属性を取得するには、属性ごとにJOINを実行する必要があるため、結果をフェッチして従来の表形式のレイアウトは複雑でコストがかかります。

この問題は、部分的なデータに対してクエリをいくつか実行し、アプリケーションでそれらを表形式のレイアウトに処理することで解決できます。600GBの製品データがある場合でも、このテーブルのすべての行のデータが必要な場合は、バッチで処理できます。

さらに進むクエリのパフォーマンスを向上させたい場合は、レポートやグローバルテキスト検索などの特定の操作を選択して、必要なデータを格納し、定期的に再生成されるインデックステーブルを準備できます。たとえば、30分ごとに実行します。

毎日どんどん安くなるので、追加のデータストレージのコストを気にする必要もありません。

アプリケーションによる操作のパフォーマンスが気になる場合は、常にErlang、C ++、Go言語を使用してデータを前処理し、後で最適化されたデータをメインアプリでさらに処理することができます。


you can always use Erlang, C++, Go Language to pre-process the dataどういう意味?DBの代わりにGo langを使用しますか?詳しく説明してもらえますか?
Green

1
全くもって同じ意見です。EAVは、特に、dbスキーマを変更せずに新しい種類の製品やパラメーターを追加できる柔軟性のレベルが必要な場合に適しています。つまり、アプリケーションを介して本番環境に住んでいます。そこに行って、それをやった。私のために働いた。遅いクエリについて...ここでキャッシュについて聞いたことがありますか?;)
pawel.kalisz 16

@Green最後の段落を編集してわかりやすくしましたが、それは、生のEAVデータを、データ変換、ツリー構造でのルックアップ、または基本的なマップを処理できる言語のプロセスに渡して、操作を非常に迅速に減らし、メモリ効率の良い方法で。ここでの詳細は、何を最適化する必要があるかによって異なります
Pawel Barcik

6

私がClass Table Inheritance意味を使用する場合:

すべての製品タイプに共通の属性を格納する、製品の1つのテーブル。次に、製品タイプごとに1つのテーブルに、その製品タイプに固有の属性を格納します。-ビル・カーウィン

ビルカーウィンの提案の中で一番気に入っているものはどれですか。問題が発生しないようにする方法を説明するために、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クラスを使用してデータベースと対話し、製品情報を取得している場合、コードの変更でリファクタリングが必要になった場合は、そのクラスのみを対象にする必要があります。


3

Productテーブルと、製品ID、追加情報名、追加情報値の3つの列を持つ個別のProductAdditionInfoテーブルを作成できます。すべての種類の製品ではなく多くの種類の製品で色が使用されている場合、それをProductテーブルのnull許容列にするか、単にProductAdditionalInfoに配置することができます。

このアプローチはリレーショナルデータベースの従来の手法ではありませんが、実際に多く使用されているのを見てきました。柔軟性があり、優れたパフォーマンスが得られます。

Steve YeggeはこれをPropertiesパターンと呼び、その使用について長い記事を書いています。


4
プロパティパターンは、別の名前のエンティティ属性値です。これは広く使用されていますが、リレーショナルデータベースに格納すると、正規化の規則に違反します。
ビルカーウィン

2
正直なところ、@ Billsの回答でEAVの説明を読んだとき、彼が何を説明しているのかよくわかりませんでした。しかし、あなたが言ったとき、3 columns: product ID, additional info name, additional info value私は概念を理解しました。そして、私は実際にこれを以前にやったことがあり、問題が発生しました。しかし、今のところ、それらの問題が何であったか思い出せません。
JD Isaacks

1
@JDIsaacksこのパターンでの一般的な問題は、すべての属性をフェッチするために必要なJOINの数がわからないことです。
オミド
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.