使用可为空的外键代替创建交集表的缺点


15

说我有以下ER图:

在此处输入图片说明

现在,如果我使用Schoolin 的外键表示关系Student,则可以具有NULL值(因为a Student 不需要属于a School),例如:

在此处输入图片说明

因此,正确的方法(基于我所读的内容)是创建一个交集表来表示这种关系,例如:

在此处输入图片说明

这样,NULL表格中就不会出现任何值School_has_Student

但是,使用可为空的外键而不是创建交集表的缺点是什么?


编辑:

我误选了(school_idstudent_id)是用于主键School_has_Student表,这使得许多关系到多。正确的主键应该是student_id

在此处输入图片说明


7
没有“正确”的方法。只有最适合您需求的方法。
MetaFight

1
我同意Doc关于错误前提的观点,但也许仍然足够明确,可以回答?
MetaFight

这里有一个错误的前提,但是很容易理顺并解释其中的区别。

我撤回了我的近距离投票,但是“因此(基于我的阅读结果,正确的方法是创建表示关系的交集表”)这句话给我的印象是,您应该告诉我们哪个应变源告诉您这是“正确”的方式。在我之前阅读的每本教科书中,1:n关系的规范方法是单个外键。还是您误会了?
布朗

@Doc Brown我不记得在哪里读过书,但我敢肯定它说相交表是正确的方法。无论如何,您能给我说一本书的名称吗,该书说应该使用一个外键来表示1:n关系(可以选择参与:1边),我很感兴趣阅读他们对这个主题的看法。
汤姆

Answers:


18

这两个模型代表不同的关系。

通过使用联接表,您正在建模多对多关系。

通过使用一个简单的外键,您正在建立一对多关系的模型。

可为空的外键的缺点是,如果您要实现这种关系,则无法对多对多关系进行建模。


根据对问题的编辑,您可以有效地将Student表拆分为两个具有相同键的表。我通常在字段太多的表上看到这一点,因此有人将它们分为两部分以便于管理(我称这是在猪身上涂口红)。

通过拆分学生表,您使第二个表成为可选表,因为第二个表中不必存在记录。这与不需要设置的字段非常相似,因为它可以为null。

如果您想要一对多的关系,那么最好使用一个表并允许学生表中的学校ID为空。即使对于外键,也没有理由避免字段为空。这表示外部关系是可选的:开发人员和DBA清楚地知道这一点,并且底层数据库引擎当然应该可以正常工作。

如果您担心加入,请不要担心。关于联接如何与空字段一起使用,存在定义明确的语义。通过使用单个表,您可以联接两个表而不是三个表。


因此,如果我要建模一对多关系(在:1端具有可选参与),尽管它可以具有NULL值,但我仍应使用外键?
汤姆(Tom)

1
@Tom是的,这正是建模的方式。尽管在技术上可以使用联接表,但数据模型允许多对多,因此您将需要触发器和数据库逻辑来防止这种情况。通过以不可能添加不正确数据的方式限制关系,您会更好。

1
我编辑了我的问题。我只student_idSchool_has_Student表中创建了一个主键,该键将关系保持为一对多。与使用外键相比,此方法有哪些缺点?
汤姆(Tom)

@Tom我编辑了答案。

6

您在上面的评论中写道:

daccess-ods.un.org daccess-ods.un.org“数据库系统基础”一书中说,如果外键列中有很多NULL值,则建议使用交集表(例如:如果98%的员工不管理部门)

当外键列中有很多NULL值时,您的程序将不得不为其处理的每条记录处理这个几乎为空的列。即使在所有情况下98%的列为空,该列也可能会占用一些磁盘空间,查询关系意味着查询该列会为您提供更多的网络流量,并且如果您使用的是从表中生成类的ORM,则程序客户端所需的空间也将超出必要。使用交集表可以避免这种情况,否则只有等效的外键不为NULL的链接记录才是必需的。

与此相反,如果您不只是几个NULL值,可以说50%或更多的关系不是NULL,则使用相交表会产生相反的效果-更大的磁盘空间,更高的复杂度导致更多的网络流量等。

因此,使用交集表只是一种优化形式,仅在特定情况下才有意义,尤其是在如今磁盘空间和内存变得更便宜,不再需要频繁使用的今天。请注意,“数据库系统基础知识”最初是20多年前写的(我发现是1994年第二版的参考),我想当时已经有建议了。在1994年之前,空间优化可能比今天更为重要,因为大容量存储仍然更加昂贵,并且计算机和网络比今天慢得多。

作为一个挑剔的注释的一个旁注:以上陈述只是试图预期“数据库系统基础知识”作者的建议时所想到的内容,我想他正在做出一个粗略的,概括性的陈述,适用于大多数系统。在某些数据库中,还有其他一些可能的优化方法,例如“稀疏列”,这使交叉表的使用变得过时了。

因此,不要误解该建议。这本书并没有告诉您{0,1}:n通常对于关系而言更喜欢使用交集表,或者-如您所写的-这是“正确的方法”。使用这样的优化,只有在您真正需要它们时,它们才会使您的程序更加复杂。


您假设数据库的实现很多,尤其是考虑到OP没有提及特定数据库。数据库很可能足够聪明,只需要为稀疏列使用少量空间即可。
gardenhead

@gardenhead:是什么让您相信这“很有可能”?
布朗

数据库已经存在了数十年并且经过高度优化,因为它们是大多数基础架构的重要组成部分。
gardenhead

@gardenhead:听起来对我来说,你在做些比我还不合理的假设。不过,请参阅我的编辑。
布朗

2

概念模型看起来像这样,少说一点是非常规的:

在此处输入图片说明

物理模型看起来像这样,令人费解的少了(除非人们仔细观察,否则人们会认为它是M:M):

在此处输入图片说明

我的建议:

如果您有很多不适用于大多数学生的列(FK或其他),请将表分成具有1:1关联的角色表。但这不是因为它们是FK,而是因为列不适用于大多数行。

否则可为空的FK是数据库的常规部分,而联接表通常用于M:M关系。

1:1 rel的常见用法是用于具有仅在实体属于某种类型时才适用的列的角色表,并出于性能或存储考虑而提取BLOB列。在FK中避免使用空值不是一种常见用法。

在此处输入图片说明


2

除了其他答案,我想指出的是,外键的空值是不明确的。它的意思是:

1)学生所在的学校(如果有)是未知的(这是'null'的标准含义-值未知)

2)知道学生是否有学校,而他们没有

如果使用null的标准含义,那么您将如何在外键模型中表示“学生没有学问”。在这种情况下,您可能必须创建一个“ no school”条目,并在school表中使用其自己的ID。(不理想)


2
《数据库系统基础知识》一书提到了对的3种解释NULL,这可能意味着:1)未知值。2)不可用或保留的值。3)不适用的属性(我认为这种解释意味着您可以NULL为外键指定a )。
汤姆(Tom)

1
这是一个有用的列表,但是null(或实际上是任何值)的语义是用户可定义的。即,它可以表示设计师所说的任何含义,而不仅限于该列表。问题是当需要多个(甚至是无意保存)时,如何区分不同的含义
Brad Thomas

那么,您是否建议我创建一个交集表,而不要使用可为空的外键?
汤姆(Tom)

@Tom是的,我相信在这种情况下会更好
Brad Thomas

@BradThomas-为避免在使用交集表时出现相同的歧义,您是否会通过交集表中具有NULL School_ID的记录来表示案例2(已知学生没有上学)?
安德鲁(Andrew)'18

1

数据库表具有称为约束的好东西。因此,在交集表中进行创建非常容易,该交集表仅允许每个学生中的一个出现在表中,但该表中有很多学校。有效地给你一个

理论上很好,但是最后您将根据所提出的问题对数据库进行建模。

如果您经常要问以下问题:“我的学校里有哪些学生”,您真的要查询整个学生表还是有一个简单的交叉表。

在数据库中:针对您提出的问题进行优化。


0

在一个用例中,使用第三个表可能确实有意义。该示例可能纯粹是假设的,但我希望它很好地说明了我的观点。假设您向students表中添加了更多列,并且在某个时候,您决定通过多个列上的复合索引来强制记录具有唯一性。您很有可能还必须包括该school_id列,并且这里的事情开始变得混乱。由于SQL的方式设计,将几个相同的记录,其中school_idNULL将成为可能。从技术角度讲,它是完全有意义的,但违反直觉,并可能导致意外结果。另一方面,在相交表上强制唯一性很容易。

最近,我不得不对这种“可选”关系进行建模,其中对唯一性约束的要求是由于时间戳列。将可空的外键留在表中会突然导致插入具有相同时间戳的记录的可能性(假设它是默认记录,设置在尚未审核/批准的记录上)-唯一的出路是删除可为空的列。

因此,正如您所看到的,这是一个相当具体的情况,正如其他人所指出的,大多数情况下,您会完全满意所有NULL值。这实际上取决于模型的特定要求。


0

除了已经提交的许多好建议之外,我个人也不喜欢外键,除非确实有必要。首先是您要引用的M:M关系。另外,调用外键,从而将表数据提取到查询中会带来更多的复杂性,并且取决于表的大小,从而降低性能。正如其他人所说,可为空的FK字段可能不受支持,并可能导致数据完整性问题。

如果您定义的学生学校未知或为空的州,则NULL不会区分那些条件。(再次回到数据完整性。)Tulains的角色表建议很优雅,并且可以干净地使用null值。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.