84669 人学习
152542 人学习
20005 人学习
5487 人学习
7821 人学习
359900 人学习
3350 人学习
180660 人学习
48569 人学习
18603 人学习
40936 人学习
1549 人学习
1183 人学习
32909 人学习
我在表格设计方面没有太多经验。我的目标是创建一个或多个满足以下要求的产品表:
支持多种类型的产品(电视,手机,电脑,...)。每种类型的产品都有不同的参数集,例如:
手机将有颜色、尺寸、重量、操作系统等。
电脑将有CPU、硬盘、内存等。
参数集必须是动态的。您可以添加或编辑任何参数。
如何在不为每种产品类型创建单独的表格的情况下满足这些要求?
@StoneHeart
我会一直使用EAV和MVC。
@Bill Karvin
你在这里提到的所有事情:
在我看来,这些都不应该出现在数据库中,因为没有任何数据库能够以适当的水平处理这些交互和要求,而应用程序的编程语言可以。
在我看来,以这种方式使用数据库就像用石头敲钉子。你可以用石头做到,但你不应该使用更精确、专门为这种活动设计的锤子吗?
可以通过对部分数据进行少量查询并将其处理成表格布局来解决这个问题。即使你有600GB的产品数据,如果你需要从这个表中获取每一行的数据,你也可以分批处理。
进一步说,如果你想提高查询的性能,你可以选择某些操作,比如报告或全局文本搜索,并准备索引表,存储所需的数据,并定期重新生成,比如每30分钟。
你甚至不需要担心额外数据存储的成本,因为它每天都在变得越来越便宜。
如果你仍然担心应用程序执行的操作的性能,你始终可以使用Erlang、C++、Go语言预处理数据,然后在主应用程序中进一步处理优化后的数据。
您至少有以下五种选项来建模您描述的类型层次结构:
单表继承:为所有产品类型使用一个表,具有足够的列来存储所有类型的所有属性。这意味着每一行上有很多列,其中大多数在任何给定的行上都是NULL。
类表继承:为产品使用一个表,存储所有产品类型的共同属性。然后,为每个产品类型使用一个表,存储特定于该产品类型的属性。
具体表继承:没有用于共同产品属性的表。相反,为每个产品类型使用一个表,存储共同产品属性和特定于产品的属性。
序列化LOB:为产品使用一个表,存储所有产品类型的共同属性。一个额外的列存储半结构化数据的BLOB,可以是XML、YAML、JSON或其他格式。这个BLOB允许您存储每个产品类型特定的属性。您可以使用复杂的设计模式来描述这个过程,比如Facade和Memento。但是无论如何,您都有一个无法在SQL中轻松查询的属性BLOB,您必须将整个BLOB取回应用程序并在那里进行排序。
实体-属性-值:为产品使用一个表,以及一个将属性旋转到行而不是列的表。EAV在关系范式方面不是一个有效的设计,但很多人仍然使用它。这是另一个答案中提到的“属性模式”。在StackOverflow上查看带有eav标签的其他问题,了解一些陷阱。
我在一个名为可扩展数据建模的演示中写了更多关于这个的内容。
关于EAV的其他想法:虽然很多人似乎喜欢EAV,但我不喜欢。它似乎是最灵活的解决方案,因此是最好的。然而,请记住这句格言TANSTAAFL。以下是EAV的一些缺点:
NOT NULL
JOIN
EAV提供的灵活性需要在其他方面做出牺牲,可能使您的代码与以更传统的方式解决原始问题的代码一样复杂(或更糟)。
而且,在大多数情况下,拥有那种程度的灵活性是不必要的。在关于产品类型的问题中,为每个产品类型创建一个表来存储特定于产品的属性会更简单,这样至少可以强制执行一些一致的结构,以适应相同产品类型的条目。
只有当每一行都允许具有不同的属性集时,我才会使用EAV。当您有一组有限的产品类型时,EAV就过度了。类表继承将是我的首选。
2019年更新:我越来越看到人们将JSON作为“许多自定义属性”问题的解决方案,我越不喜欢这个解决方案。即使使用特殊的JSON函数来支持它们,查询也变得过于复杂。与存储在常规行和列中相比,存储JSON文档需要更多的存储空间。
基本上,在关系数据库中,这些解决方案都不容易或高效。拥有“可变属性”的整个概念与关系理论根本不一致。
归根结底,您必须根据对数据的查询方式选择其中一种解决方案,这是基于对您的应用程序来说最不糟糕的解决方案。因此,在选择数据库设计之前,您需要知道如何查询数据。没有一种解决方案是“最佳”的,因为任何一种解决方案都可能是某个应用程序的最佳选择。
@StoneHeart
我会一直使用EAV和MVC。
@Bill Karvin
你在这里提到的所有事情:
在我看来,这些都不应该出现在数据库中,因为没有任何数据库能够以适当的水平处理这些交互和要求,而应用程序的编程语言可以。
在我看来,以这种方式使用数据库就像用石头敲钉子。你可以用石头做到,但你不应该使用更精确、专门为这种活动设计的锤子吗?
可以通过对部分数据进行少量查询并将其处理成表格布局来解决这个问题。即使你有600GB的产品数据,如果你需要从这个表中获取每一行的数据,你也可以分批处理。
进一步说,如果你想提高查询的性能,你可以选择某些操作,比如报告或全局文本搜索,并准备索引表,存储所需的数据,并定期重新生成,比如每30分钟。
你甚至不需要担心额外数据存储的成本,因为它每天都在变得越来越便宜。
如果你仍然担心应用程序执行的操作的性能,你始终可以使用Erlang、C++、Go语言预处理数据,然后在主应用程序中进一步处理优化后的数据。
您至少有以下五种选项来建模您描述的类型层次结构:
单表继承:为所有产品类型使用一个表,具有足够的列来存储所有类型的所有属性。这意味着每一行上有很多列,其中大多数在任何给定的行上都是NULL。
类表继承:为产品使用一个表,存储所有产品类型的共同属性。然后,为每个产品类型使用一个表,存储特定于该产品类型的属性。
具体表继承:没有用于共同产品属性的表。相反,为每个产品类型使用一个表,存储共同产品属性和特定于产品的属性。
序列化LOB:为产品使用一个表,存储所有产品类型的共同属性。一个额外的列存储半结构化数据的BLOB,可以是XML、YAML、JSON或其他格式。这个BLOB允许您存储每个产品类型特定的属性。您可以使用复杂的设计模式来描述这个过程,比如Facade和Memento。但是无论如何,您都有一个无法在SQL中轻松查询的属性BLOB,您必须将整个BLOB取回应用程序并在那里进行排序。
实体-属性-值:为产品使用一个表,以及一个将属性旋转到行而不是列的表。EAV在关系范式方面不是一个有效的设计,但很多人仍然使用它。这是另一个答案中提到的“属性模式”。在StackOverflow上查看带有eav标签的其他问题,了解一些陷阱。
我在一个名为可扩展数据建模的演示中写了更多关于这个的内容。
关于EAV的其他想法:虽然很多人似乎喜欢EAV,但我不喜欢。它似乎是最灵活的解决方案,因此是最好的。然而,请记住这句格言TANSTAAFL。以下是EAV的一些缺点:
NOT NULL
)。JOIN
。EAV提供的灵活性需要在其他方面做出牺牲,可能使您的代码与以更传统的方式解决原始问题的代码一样复杂(或更糟)。
而且,在大多数情况下,拥有那种程度的灵活性是不必要的。在关于产品类型的问题中,为每个产品类型创建一个表来存储特定于产品的属性会更简单,这样至少可以强制执行一些一致的结构,以适应相同产品类型的条目。
只有当每一行都允许具有不同的属性集时,我才会使用EAV。当您有一组有限的产品类型时,EAV就过度了。类表继承将是我的首选。
2019年更新:我越来越看到人们将JSON作为“许多自定义属性”问题的解决方案,我越不喜欢这个解决方案。即使使用特殊的JSON函数来支持它们,查询也变得过于复杂。与存储在常规行和列中相比,存储JSON文档需要更多的存储空间。
基本上,在关系数据库中,这些解决方案都不容易或高效。拥有“可变属性”的整个概念与关系理论根本不一致。
归根结底,您必须根据对数据的查询方式选择其中一种解决方案,这是基于对您的应用程序来说最不糟糕的解决方案。因此,在选择数据库设计之前,您需要知道如何查询数据。没有一种解决方案是“最佳”的,因为任何一种解决方案都可能是某个应用程序的最佳选择。