假设表car与表electric_cargas_carhybrid_car具有一对一的关系。如果carelectric_car,那么它将不再出现在gas_carhybrid_car等中。

这样的设计是否有问题?将来可能会发生一些问题吗?

#1 楼

不同类型的汽车是一个普遍问题的实例,该问题在数据建模中一遍又一遍地浮出水面。在ER建模中称为“一般化/专业化”,在对象建模中称为“超类/子类”。

对象建模者使用对象模型中内置的继承功能来轻松解决问题。子类只是扩展了超类。

关系建模器面临一个问题。如何设计表以模仿继承带来的好处?

最简单的技术称为单表继承。有关所有类型汽车的数据被分组到一个汽车表中。有一个列car_type,将一个类型的所有汽车组合在一起。汽车不能属于一种以上的类型。如果某列与例如电动汽车无关,则在与电动汽车有关的行中将其保留为NULL。大量NULL的存在会给存储开销增加一点点,而给检索开销增加一点点。如果对可空列进行布尔测试,则开发人员可能必须学习SQL三值逻辑。起初这令人困惑,但是已经习惯了。

还有另一种技术,称为类表继承。在此设计中,除了用于所有表的合并表car之外,还有用于gas_car,electric_car和hybrid_car的单独表。当您需要有关特定类型汽车的所有数据时,可以将汽车表与适当的专用表结合在一起。此设计中的NULL较少,但您进行的连接更多。此技术在较大和更复杂的情况下效果更好。

第三种技术称为共享主键。该技术通常与类表继承结合使用。子类的专用表具有car表中相应条目的主键副本作为其主键。这个id列既可以声明为主键也可以声明为外键。 。

超类和子类在现实世界中始终存在。不要害怕但是请测试您的初始设计的性能。如果您的第一次尝试既简单又合理,则可以对其进行调整以加快速度。

评论


优秀的答案在这里。提示:彻底记录这些设计决策。无论采用哪种方法,当有人检查数据库结构时,它都不是显而易见的。一些数据库(例如Postgres)使您能够将注释与列,表等的元数据绑定在一起。

–罗勒·布尔克
17/12/18在23:05



您没有解决限制电动汽车成为混合动力汽车的限制。您需要一个单独的表。

– jmoreno
17年12月19日在10:30

你是对的。如果将car_type字段添加到cars表,则可以将cars限制为仅属于一种类型,但要以偏离完全规范化为代价。一个好的DBMS可以让您定义一个检查约束,以防止一辆车被输入多个专用表中。有一些开销,您要添加新车。

– Walter Mitty
17年12月19日在11:25

@WalterMitty但没有car_type字段,在检索数据时如何知道要在哪个表中查找详细信息?您是否必须阅读所有三个表才能查看哪个表具有有关该特定汽车记录的数据?

–Josh Part
17年12月20日在3:51

我说的是您想要一种特定类型(例如电动汽车)的所有数据的情况。您将具有electric_cars的汽车加入,但非电动汽车将从加入中退出。您假定的情况有所不同,您需要有关一种以上汽车类型的特定数据。

– Walter Mitty
17年12月20日在11:45

#2 楼

在模型中有足够多的实体子类型来反映要建模的数据的真实性是没有错的。问题不是子类型是否是一种不好的做法。

例如,在您的示例中,您如何使用奥迪A4 eTron这样的插电式混合动力车?这是“电动汽车”还是“混合动力汽车”?

您还必须问自己的另一个问题是,为什么您要分型?您的子类型中有多少个不同的谓词?这些谓词是否在子类型之间共享?这种情况可能会变得复杂。

数据库设计中未使用子类型进行分类。您可以使用代码,代码表的外键或标志进行分类。子类型用于为不同类型的关注事物建模不同的谓词集。如果您仅将子类型用于分类,那么这是一个不好的做法。

如果您的子类型清楚明确地为数据库关心的事物建模不同的谓词集,那么这是一个很好的选择练习,无论您需要多少个子类型。

评论


谢谢,我担心自己会给自己设置陷阱。我的问题是每个子类型都会有很多列。有些会重叠,我会把它们放在汽车表中,但很多不会,并且会放在子类型表中。例如,它将类似于存储汽车类型的基本部件。电动汽车发动机可以有100份,汽油汽车发动机有75份,混合动力有125份。 50个零件将共用并存储在汽车中,而50、25和75将存储在electric_car,gas_car和hybrid_car表中

– Arthur Tarasov
17/12/18在12:22