この問題 (カテゴリごとに異なるプロパティ) に対するベスト プラクティスは何ですか?

StackOverflow https://stackoverflow.com/questions/221584

質問

いくつかのカテゴリに属する​​製品がいくつかあります。

各カテゴリは異なるプロパティを持つことができます。

例えば、

  • カテゴリー 特性を持っています 、 力、 ...
  • カテゴリー ペット 特性を持っている 重さ, , ...

カテゴリ数は10~15程度です。各カテゴリの物件数は 3 ~ 15 です。商品数が非常に多いです。

このアプリの主な要件は、優れた検索機能です。カテゴリを選択し、このカテゴリの各プロパティの基準を入力します。

このシナリオ用にデータベースを設計する必要があります。(SQLサーバー2005)

役に立ちましたか?

解決

古典的な設計アプローチは次のようになります (星印は主キー列を示します)。

Product
  ProductId*
  CategoryId: FK to Category.CategroyId
  Name

Category
  CategoryId*
  Name

Property
  PropertyId*
  Name
  Type

CategoryProperty
  CategoryId*: FK to Category.CategoryId
  PropertyId*: FK to Property.PropertyId

ProductProperty
  ProductId*: FK to Product.ProductId
  PropertyId*: FK to Property.PropertyId
  ValueAsString

すべてのプロパティ値が文字列として DB に送信され、型変換情報がプロパティ テーブルに保存されるという事実を受け入れることができる場合は、このレイアウトで十分です。

クエリは次のようになります。

SELECT
   Product.ProductId,
   Product.Name AS ProductName,
   Category.CategoryId,
   Category.Name AS CategoryName,
   Property.PropertyId,
   Property.Name AS PropertyName,
   Property.Type AS PropertyType,
   ProductProperty.ValueAsString
FROM
   Product 
   INNER JOIN Category         ON Category.CategoryId = Product.CategoryId
   INENR JOIN CategoryProperty ON CategoryProperty.CategoryId = Category.CategoryId
   INNER JOIN Property         ON Property.PropertyId = CategoryProperty.PropertyId
   INNER JOIN ProductProperty  ON ProductProperty.PropertyId = Property.PropertyId
                                  AND ProductProperty.ProductId = Product.ProductId
WHERE
   Product.ProductId = 1

より多くの WHERE 条件を指定するほど (結合的に、例:AND を使用すると)、クエリが高速になります。つまり、テーブルに適切にインデックスを作成した場合です。

現状では、このソリューションは全文インデックス作成の状況には理想的ではありません。ProductId に関連付けられたすべてのテキストをより非正規化された方法で保存する追加のテーブルがここで役立ちます。このテーブルは、ProductProperty テーブルの変更をリッスンするトリガーを通じて更新する必要があります。

他のヒント

アプリケーションのユーザーの場合 もっている 検索する前にカテゴリを選択するには、製品をカテゴリごとに異なるデータベース テーブルに分割します。この解決策は、カテゴリ自体に共通点がほとんどないという事実からもわかります。カテゴリ別に分類すると、ユーザーがペットを探しているときに車の中を検索する無駄な時間がなくなるため、各検索が大幅に高速化されます。

製品をカテゴリに分割したら、各カテゴリの製品の共通プロパティを使用してテーブルを簡単に作成できます。アプリケーションのユーザー インターフェイスは動的である必要があります (私は Web フォームを考えています)。ユーザーがカテゴリを選択すると、ユーザーが選択できるプロパティが変化する必要があります。

複数のカテゴリにリストしたい製品がある場合、この解決策ではテーブル内に重複したデータが作成されることに注意してください。データベースを設計する場合、速度と正規化の間にはトレードオフの関係があります。もし、あんたが しないでください 複数のカテゴリに当てはまる商品がある場合、これが (検索速度の点で) 最も速い解決策になると思います。

ほとんどの人は、Entity-Attribute-Value (EAV) 設計のバリエーションを使用することを推奨しています。この設計はあなたの状況には過剰であり、たとえば次のような多くの問題を引き起こします。

  • 属性のデータ型を定義することはできません。整数属性として「バナナ」と入力できます
  • 属性を必須として宣言することはできません(つまり、従来のテーブルでは NOT NULL)
  • 属性に対して外部キー制約を宣言することはできません

カテゴリの数が少ない場合は、Bogdan Maxim の回答のソリューション A を使用することをお勧めします。つまり、すべてのカテゴリに共通の属性を持つ 1 つのテーブル Products を定義し、カテゴリ固有の属性を格納するためにカテゴリごとに 1 つの追加テーブルを定義します。

カテゴリの数が無限にある場合、または Products の行ごとに異なる属性セットをサポートする必要がある場合にのみ、EAV が適切なソリューションとなります。ただし、EAV は正規化のいくつかのルールに違反するため、リレーショナル データベースをまったく使用していないことになります。

本当にそこまでの柔軟性が必要な場合は、データを XML で保存することをお勧めします。実際、RDF やセマンティック Web フレームワークを検討してみるとよいでしょう。 ゴマ.

検討してみてはいかがでしょうか エンティティの属性値 任意の名前と値の属性ペアを各製品に「タグ付け」できる配置のタイプです。

これを試すことができます。あなたの質問の実際の詳細はあまりわかりませんが、誰かがもう少しうまく翻訳できるよう手伝ってくれるかもしれません。

5テーブル。3 はデータの保存用、2 はデータ間のマッピングの保存用です。

tProduct 
  productID
  <other product details>

tCategory
  categoryID
  <other category details>

tProperty
  propertyID
  <other property details>

tProductXCategory
  productyID
  categoryID

tCategoryXProperty
  categoryID
  propertyID

クエリではマッピング テーブルを使用してデータを結合する必要がありますが、これにより、カテゴリ、プロパティ、製品の間にさまざまな多対多の関係を持たせることができます。

検索のパフォーマンスを向上させるには、ストアド プロシージャまたはパラメータ化されたクエリを使用します。

カテゴリとプロパティを柔軟に設定したい場合は、次のテーブルを作成する必要があります。

  • 製品:製品番号
  • カテゴリー:カテゴリID、プロダクトID
  • 財産:プロパティID、カテゴリID

複数の製品でカテゴリを共有したい場合は、n:m 結合のリンク テーブルを作成する必要があります。

  • 製品カテゴリポインタ:ProdCatID、ProductID、CategoryID。

クエリでいくつかの結合を行う必要がありますが、適切なインデックスを使用すれば、データを高速にクエリできるはずです。

もっとオブジェクト指向的なものを試してみることもできます。

1.Products のベース テーブルを定義する

Products(ProductID, CategoryID, <any other common properties>)

2.テーブルのカテゴリを定義する

Categories(CategoryID, Name, Description, ..)

ここからは多くのオプションがあり、そのほとんどすべてがデータベースの正規化を破壊します。

解決策 A.

新しい製品を追加する必要がある場合、メンテナンスは悪夢のような作業になります

A1.カテゴリごとに個別のテーブルを定義する

Cars(CarID, ProductID, ..) Pets(PetID, ProductID, ..)

A2.データを使用するには、リレーションシップに基づいてテーブルを結合します。

SELECT <fields> FROM Cars INNER JOIN Products ON Cars.ProductID = Products.ProductID

解決策 B.

さまざまな種類の物件(つまり、int、varchar など)

B1.プロパティのテーブルを定義する

CategoryProperty (CPID, Name, Type)

B2.カテゴリとプロパティ間の関連付けを保持するテーブルを定義します。

PropertyAssociation (CPID, PropertyID)

B12.プロパティを保持するテーブルを定義します (B1 および B2 の代替)

Properties(CategoryID, PropertyID, Name, Type)

B3.プロパティのタイプ (int、double、varchar など) ごとに値テーブルを追加します。

PropertyValueInt(ProductID, CPID, PropertyID, Value) - intの場合PropertyValueString(ProductID, CPID, PropertyID, Value) - 文字列の場合PropertyValueMoney(ProductID, CPID, PropertyID, Value) - お金のために

B4.すべてのテーブルを結合して、目的のプロパティを取得します。

このアプローチを使用すると、すべてのプロパティを別のテーブルで管理する必要がなく、プロパティの値の型を管理する必要がなくなります。基本的に、関係するすべてのテーブルはルックアップ テーブルになります。欠点は、各値を取得するには、すべての値の型に対して「Case」を実行する必要があることです。

これらの記事を念頭に置いてください (ここ そして ここ) これらのアプローチのいずれかを選択する場合。 このフォーラムの投稿 これも興味深いものであり、ローカリゼーションに関するものですが、何らかの形で主題に関連しています。

を使用することもできます トマラックの答え 必要に応じて、強力な型指定を追加します。

最近これを行う必要があり、3つのエンティティがあるNHibernateを使用しています

製品カテゴリ オプション オプションカテゴリ

製品には 1* カテゴリーがあります

製品には 1* オプションがあります

オプションには 1 つの OptionCategory があります

これを設定すると、Nhibernate キャッシュを使用できるようになります

乾杯

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top