我有一个名为汽车的表,但每辆车都有数百个属性,并且它们会随着时间的推移而不断增加(马力、扭矩、空调、电动车窗等......)我的表将每个属性作为一列。当我有数千行和数百列时,这是正确的方法吗?此外,我将每个属性都设为一列,以便于进行高级搜索/过滤。
使用MySQL数据库。
谢谢
我想显而易见的问题是:为什么没有表 car_attrs(car, attr, value)?每个属性都是一行。大多数查询可以重写以使用这种形式。
恕我直言,这是一个有趣的问题,答案可能取决于您的特定数据模型和实现。在这种情况下,最重要的因素是数据密度。
平均每行实际填满多少?
让我们使用您提到的案例,并进行一些模拟。
在第一种情况下,范围分区,其想法是基于范围或使用来实现分区。作为按使用分区的示例,假设检索最多的字段是 Model、Year、Maker 和 Color。这些字段可能构成您的主 [CAR] 表,ID 字段的所有者将专门识别车辆。现在假设发动机、马力、扭矩和气缸有时也用于搜索,但不那么频繁。这些可能存在于辅助表 [CAR_INFO_1] 上,该辅助表通过 CAR_ID 字段(外键)的存在与第一个表相关联。继续创建所需数量的分区。
优点:查询更简单。如果您进行联合查询(例如在 VIEW 中),您可以合并有关车辆的所有信息。
缺点:维护。每个新字段都必须在模型本身中实现,并且您需要更新的数据模型来定位您需要的字段实际存储的位置(或将其抽象到视图中。)
元数据格式更加优雅,但需要更多的数据库引擎。查看@JayC 和@Nitzan Shaked 的答案以了解详细信息。
优点:100% 的数据密度。您永远不会有空的数据值。还维护 - 通过将其作为一行添加到元数据标识符表中来创建新属性。数据结构也不太复杂。
缺点:复杂的查询,以及更复杂的执行计划。假设您需要 2010 年生产的所有蓝色福特汽车。在第一种情况下这将是非常微不足道的:
SELECT * FROM CAR WHERE Model='Ford' AND Year='2010' AND Color='Blue'
现在对元数据结构化模型进行相同的查询:
假设这两个表存在,
CAR_METADATA_TYPE
ID DESC
1 'Model'
2 'Year'
3 'Color'
和
CAR_METADATA [CAR_ID], [METADATA_TYPE_ID], [VALUE]
查询本身会是这样的:
SELECT * FROM CAR, CAR_METADATA [MP1], CAR_METADATA [MP2], CAR_METADATA [MP3]
WHERE MP1.CAR_ID = CAR.ID AND MP1.METADATA_TYPE_ID = 1 AND MP1.Value='Ford'
AND MP2.CAR_ID = CAR.ID AND MP2.METADATA_TYPE_ID = 2 AND MP2.Value='2010'
AND MP3.CAR_ID = CAR.ID AND MP3.METADATA_TYPE_ID = 3 AND MP3.Value='Blue'
所以,这一切都取决于你的需要。但鉴于您的情况,我的建议是元数据格式。
(但先做一个模型清理 - 没有重复的字段,1:N 数据在他们自己的表上,而不是像 Color1、Color2、Color3 这样的内联字段;))
如果都是关于特性的,创建一个features
表,将所有特性列为行并给它们某种自动 id,并创建一个car_features
带有外键的cars
表,以及将features
汽车与特性相关联的表,可能还有任何与关系相关的值(一个乘客电动座椅等)。
如果您曾经更改过属性,请考虑将它们存储在 XML blob 或文本结构中的一列中。这种结构不是关系型的。然后,最重要的属性将在其他列中复制,因此您可以制作查询以对其进行搜索,因为 Blob 无法从 SQL 查询中搜索。这将减少该表中的列数量,并允许在不更改数据库模式的情况下进行扩展。
正如其他人所建议的那样,如果您想要表中的所有属性,则使用属性表来定义它们。然后将取决于您的要求和应用程序的需要。