这个问题的最佳实践是什么(不同类别的不同属性)?

时间:2008-10-21 11:56:36

标签: sql sql-server database database-design entity-attribute-value

我有一些产品属于某个类别。

每个类别都可以有不同的属性。

例如,

  • 类别汽车具有属性颜色, 权力,......
  • 类别宠物具有属性重量年龄,...

类别数量约为10-15。 每个类别的属性数量为3-15。 产品数量非常大。

此应用程序的主要要求是非常好的搜索。我们将选择类别,并为此类别中的每个属性输入标准。

必须为此方案设计数据库。 (SQL Server 2005)

8 个答案:

答案 0 :(得分:13)

经典的设计方法是(星号代表主键列):

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

如果您可以接受这样的事实:每个属性值都将作为字符串转到数据库并且类型转换信息存储在Property表中,那么这种布局就足够了。

查询将是这样的:

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表中的更改的触发器进行更新。

答案 1 :(得分:8)

如果应用程序的用户在他们可以搜索之前选择一个类别,我会按类别将您的产品分成不同的数据库表。这种解决方案也表明,类别本身的共同点很少。按类别细分它也会使每次搜索更快,因为当你的用户正在寻找宠物时,不会浪费时间搜索汽车。

将产品拆分为类别后,应使用每个类别中产品的公共属性轻松创建表格。应用程序的用户界面应该是动态的(我正在考虑Web表单),因为用户可以选择的属性应该在用户选择类别时更改。

请注意,如果您要将产品列在多个类别中,此解决方案将导致表格中出现重复数据。在设计数据库时,需要在速度和标准化之间进行权衡。如果您没有的产品适合多个类别,那么我认为这将是最快的解决方案(就搜索速度而言)。

答案 2 :(得分:2)

大多数人都建议使用实体 - 属性 - 值(EAV)设计的变体。这种设计对你的情况来说太过分了,它引入了一大堆问题,例如:

  • 您无法定义属性的数据类型;您可以为整数属性输入“banana”
  • 您不能将属性声明为必需属性(即传统表中的NOT NULL)
  • 您无法在属性
  • 上声明外键约束

如果您的类别数量较少,最好在Bogdan Maxim的答案中使用解决方案A.也就是说,定义一个表Products,其中包含所有类别共有的属性,以及每个类别的一个附加表,以存储特定于类别的属性。

只有当您拥有无限数量的类别或者您必须在产品中每行支持不同的属性集时,EAV才是一个很好的解决方案。但是你根本没有使用关系数据库,因为EAV违反了几个规范化规则。

如果您确实需要这么大的灵活性,那么最好将数据存储在XML中。实际上,您可能会研究像Sesame这样的RDF和语义Web框架。

答案 3 :(得分:1)

您可能需要考虑Entity-Attribute-Value类型的排列,您可以使用任意名称/值对属性“标记”每个产品。

答案 4 :(得分:1)

你可以试试这个。我不太确定你的问题的实际细节,也许有人可以帮你翻译一点。

5张桌子。 3用于存储数据,2用于存储数据之间的映射。

tProduct 
  productID
  <other product details>

tCategory
  categoryID
  <other category details>

tProperty
  propertyID
  <other property details>

tProductXCategory
  productyID
  categoryID

tCategoryXProperty
  categoryID
  propertyID

您的查询需要使用映射表加入数据,但这将允许您在类别,属性和产品之间建立不同的多对多关系。

使用存储过程或参数化查询来提高搜索效果。

答案 5 :(得分:0)

如果您希望灵活处理类别和属性,则应创建以下表格:

  • 产品:ProductID
  • 类别:CategoryID,ProductID
  • property:PropertyID,CategoryID

当您想要共享mroe而不是一个产品的类别时,您必须为n:m join创建一个链接表:

  • productCategoryPointer:ProdCatID,ProductID,CategoryID。

您必须在查询中加入一些联接,但如果使用正确的索引,您应该能够快速查询数据。

答案 6 :(得分:0)

你可以尝试一些更面向对象的东西。

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。为Properties

定义一个表

CategoryProperty (CPID, Name, Type)

B2。定义一个表来保存Categories和Properties

之间的关联

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”。

在选择任何这些方法时,请记住这些文章(herehere)。 This forum post也很有趣并且与某个主题有关,即使它是关于本地化的。

如果您认为有必要,也可以使用Tomalak's answer并添加强类型。

答案 7 :(得分:0)

我最近不得不这样做,我使用NHibernate,我有三个实体

产品类别选项OptionCategory

产品有1 *类别

产品有1 *选项

Option有1个OptionCategory

设置完成后,您可以使用Nhibernate缓存

干杯