各製品に多くのパラメータがあるさまざまな種類の製品の製品テーブルを設計する方法
-
22-08-2019 - |
質問
私はテーブルデザインの経験があまりありません。私の目標は、以下の要件を満たす 1 つ以上の製品テーブルを作成することです。
さまざまな種類の製品 (テレビ、電話、PC など) をサポートします。製品の種類ごとに、次のような異なるパラメータのセットがあります。
携帯電話には色、サイズ、重量、OS...
PCにはCPU、HDD、RAMが搭載されています...
パラメータのセットは動的である必要があります。任意のパラメータを追加または編集できます。
製品の種類ごとに個別のテーブルを用意せずに、どうすればこれらの要件を満たすことができるでしょうか?
解決
説明する型階層をモデル化するには、少なくとも次の 5 つのオプションがあります。
単一テーブルの継承:すべての製品タイプに対して 1 つのテーブル。すべてのタイプのすべての属性を格納するのに十分な列があります。これはつまり たくさん 列のほとんどは、特定の行で NULL です。
クラステーブルの継承:製品用の 1 つのテーブルには、すべての製品タイプに共通の属性が格納されます。次に、製品タイプごとに 1 つのテーブルがあり、その製品タイプに固有の属性が保存されます。
具象テーブルの継承:一般的な製品属性のテーブルはありません。代わりに、製品タイプごとに 1 つのテーブルがあり、共通の製品属性と製品固有の属性の両方が保存されます。
シリアル化された LOB:製品用の 1 つのテーブル。すべての製品タイプに共通の属性が保存されます。追加の 1 つの列には、半構造化データの BLOB が XML、YAML、JSON、またはその他の形式で保存されます。この BLOB を使用すると、各製品タイプに固有の属性を保存できます。これを説明するには、Facade や Memento などの派手なデザイン パターンを使用できます。しかし、SQL 内で簡単にクエリできない属性の塊があるにもかかわらず、BLOB 全体をアプリケーションにフェッチして戻し、そこで並べ替える必要があります。
エンティティの属性値:製品用の 1 つのテーブルと、列ではなく行に属性をピボットする 1 つのテーブル。EAV はリレーショナル パラダイムに関して有効な設計ではありませんが、それでも多くの人が EAV を使用しています。これは、別の回答で言及されている「プロパティ パターン」です。他の質問を参照してください eavタグ いくつかの落とし穴については、StackOverflow を参照してください。
これについてはプレゼンテーションで詳しく書きましたが、 拡張可能なデータモデリング.
EAV に関するその他の考え:多くの人は EAV を支持しているようですが、私はそうではありません。これは最も柔軟なソリューションであるため、最良であると思われます。ただし、この格言を心に留めておいてください タンスターフル. 。EAV の欠点は次のとおりです。
- 列を必須にする方法はありません(
NOT NULL
). - SQL データ型を使用してエントリを検証する方法はありません。
- 属性名の綴りが一貫していることを保証する方法はありません。
- 特定の属性の値に外部キーを設定する方法はありません。ルックアップテーブル用。
- 従来の表形式レイアウトでの結果の取得は複雑でコストがかかります。複数の行から属性を取得するには次の操作を行う必要があるからです。
JOIN
属性ごとに。
EAV が提供する柔軟性の程度には、他の領域での犠牲が必要となり、おそらくコードが、より従来的な方法で元の問題を解決する場合と同じくらい (またはさらに悪化) 複雑になります。
そしてほとんどの場合、そこまでの柔軟性は必要ありません。製品タイプに関する OP の質問では、製品固有の属性について製品タイプごとにテーブルを作成する方がはるかに簡単なので、少なくとも同じ製品タイプのエントリに対しては、一貫した構造が適用されます。
EAV を使用するのは次の場合のみです すべての行 潜在的に個別の属性セットを持つことを許可する必要があります。製品タイプのセットが有限である場合、EAV は過剰です。クラステーブルの継承が私の第一選択です。
2019 年のアップデート:「カスタム属性が多い」問題の解決策として JSON を使用している人を見るほど、私はその解決策が好きではなくなります。特別なメソッドを使用する場合でも、クエリが複雑になりすぎます。 JSON関数 彼らをサポートするために。JSON ドキュメントを保存するには、通常の行と列に保存する場合に比べて、より多くのストレージ スペースが必要になります。
基本的に、リレーショナル データベースでは、これらのソリューションはいずれも簡単または効率的ではありません。「可変属性」を持つという考え方全体が、関係理論と根本的に対立しています。
結局のところ、どれが最も害が少ないかに基づいて解決策の 1 つを選択する必要があるということです。 あなたの アプリ。したがって、データベース設計を選択する前に、データをクエリする方法を知っておく必要があります。どのソリューションも特定のアプリケーションに最適である可能性があるため、「最適な」ソリューションを 1 つ選択する方法はありません。
他のヒント
@石の心
私ならここではずっと EAV と MVC を使います。
@ビル・カービン
EAVの欠点の一部は次のとおりです。
No way to make a column mandatory (equivalent of NOT NULL). No way to use SQL data types to validate entries. No way to ensure that attribute names are spelled consistently. No way to put a foreign key on the values of any given attribute, e.g.
ルックアップテーブル用。
あなたがここで言及したことはすべて次のとおりです。
- データ検証
- 属性名のスペル検証
- 必須の列/フィールド
- 依存属性の破棄の処理
私の意見では、アプリケーションのプログラミング言語のように適切なレベルでこれらの対話や要件を処理できるデータベースは存在しないため、データベースにはまったく属していません。
私の意見では、このようにデータベースを使用することは、石を使って釘を打つようなものです。石を使ってそれを行うこともできますが、より正確でこの種の作業のために特別に設計されたハンマーを使用することを想定していませんか?
従来の表形式のレイアウトでの結果の結果は複雑で高価です。複数の行から属性を取得するには、各属性に結合する必要があるためです。
この問題は、部分データに対していくつかのクエリを作成し、アプリケーションでそれらを表形式のレイアウトに処理することで解決できます。600 GB の製品データがある場合でも、このテーブルのすべての行のデータが必要な場合は、バッチで処理できます。
さらに進む クエリのパフォーマンスを向上させたい場合は、次のような特定の操作を選択できます。レポートやグローバル テキスト検索を作成し、必要なデータを保存し、定期的に (たとえば 30 分ごとに) 再生成されるインデックス テーブルを準備します。
追加のデータ ストレージのコストを気にする必要はありません。データ ストレージは毎日どんどん安くなります。
アプリケーションによって実行される操作のパフォーマンスが依然として懸念される場合は、いつでも Erlang、C++、Go 言語を使用してデータを前処理し、後で最適化されたデータをメイン アプリでさらに処理することができます。
私が使うなら Class Table Inheritance
意味:
製品用の 1 つのテーブルには、すべての製品タイプに共通の属性が格納されます。次に、製品タイプごとに 1 つのテーブルがあり、その製品タイプに固有の属性が保存されます。-ビル・カーウィン
私はビル・カーウィンの提案の中でこれが一番好きです。1 つの欠点はある程度予想できるので、問題にならないようにする方法を説明します。
1 つのタイプにのみ共通する属性が、その後 2、さらに 3 に共通になる場合、どのような緊急時対応計画を立てておく必要がありますか?
例えば:(これは単なる例であり、実際の問題ではありません)
家具を販売する場合は、椅子、ランプ、ソファ、テレビなどを販売する可能性があります。当店で取り扱っている消費電力があるタイプはテレビタイプだけかもしれません。だから私は power_consumption
の属性 tv_type_table
. 。しかしその後、私たちはホームシアターシステムも取り扱い始めました。 power_consumption
財産。OK、それはもう 1 つの製品にすぎないので、このフィールドを stereo_type_table
現時点ではそれがおそらく最も簡単だからです。しかし、時間が経つにつれて、より多くの電子機器を持ち歩くようになると、私たちは次のことに気づきます。 power_consumption
十分に広いので、 main_product_table
. 。私は今どうすればいい?
フィールドを main_product_table
. 。電子機器をループし、それぞれの電子機器から正しい値を入力するスクリプトを作成します。 type_table
に main_product_table
. 。次に、それぞれの列からその列を削除します type_table
.
今、いつも同じものを使っていたら GetProductData
データベースと対話して製品情報を取得するクラス。コード内の変更でリファクタリングが必要になった場合、その変更はそのクラスに対してのみ行われます。
あなたは3列を持つ製品のテーブルと別のProductAdditionInfoテーブルを持つことができます。色は製品の多くではなく、すべての種類で使用されている場合は、それが製品テーブル内のNULL可能列で持っているか、単にProductAdditionalInfoにそれを置くことができます。
このアプローチは、リレーショナル・データベースのための伝統的な手法ではありませんが、私はそれが実際に多く使用さ見てきました。それは柔軟でかつ良好な性能を持つことができます。
スティーブ・イェジはプロパティのパターン href="http://steve-yegge.blogspot.com/2008/10/universal-design-pattern.html#redacted" rel="nofollowこのと、それを使用する方法について長い記事を書きました。