173

前几天我在想规范化,我突然想到,我想不出数据库中应该存在 1:1 关系的时间。

  • Name:SSN? 我会把它们放在同一张桌子上。
  • PersonID:AddressID? 再次,同一张桌子。

我可以想出无数个 1:many 或 many:many 的例子(带有适当的中间表),但绝不是 1:1。

我错过了一些明显的东西吗?

4

26 回答 26

176

1:1 关系通常表明您出于某种原因对较大的实体进行了分区。通常是因为物理模式中的性能原因,但如果预计大量数据同时“未知”(在这种情况下您有 1:0或 1:1,但仅此而已)。

作为逻辑分区的示例:您有关于员工的数据,但需要收集更大的数据集,当且仅当他们选择拥有健康保险时。我会将有关健康保险的人口统计数据保存在不同的表中,以便更轻松地进行安全分区,并避免在与保险无关的查询中拖拽这些数据。

物理分区的一个示例是托管在多个服务器上的相同数据。我可以将健康保险人口统计数据保存在另一个州(例如,人力资源办公室所在的州),并且主数据库可能只能通过链接服务器链接到它......避免将敏感数据复制到其他位置,但使其可用于(假设这里很少)需要它的查询。

每当您的查询需要较大实体的一致子集时,物理分区就很有用。

于 2009-02-05T19:14:22.010 回答
132

原因之一是数据库效率。拥有 1:1 的关系允许您拆分在行/表锁定期间将受到影响的字段。如果表 A 有大量更新,而表 b 有大量读取(或有来自另一个应用程序的大量更新),那么表 A 的锁定不会影响表 B 中发生的事情。

其他人提出了一个很好的观点。取决于应用程序等如何影响系统,安全性也可能是一个很好的理由。我倾向于采用不同的方法,但这可能是一种限制对某些数据的访问的简单方法。在紧要关头拒绝访问某个表真的很容易。

我关于它的博客条目。

于 2009-02-05T19:11:38.833 回答
52

稀疏性。数据关系在技术上可能是 1:1,但不必为每一行都存在相应的行。因此,如果您有 2000 万行并且某些值仅存在于其中的 0.5%,那么如果将这些列推送到可以稀疏填充的表中,则空间节省是巨大的。

于 2009-02-05T19:16:10.680 回答
27

大多数排名靠前的答案都为 1:1 关系提供了非常有用的数据库调整和优化原因,但我只想关注自然发生 1:1 关系的“野外”示例。

请注意大多数这些示例的数据库实现的一个重要特征:没有保留有关 1:1 关系的历史信息。也就是说,这些关系在任何给定时间点都是 1:1。如果数据库设计者想要记录关系参与者随时间的变化,那么关系就变成 1:M 或 M:M;他们失去了 1:1 的本性。了解了这一点,这里是:

  • “Is-A”或超类型/子类型或继承/分类关系:此类别是当一个实体是另一个实体的特定类型时。例如,可以有一个 Employee 实体,其属性适用于所有员工,然后是不同的实体来指示特定类型的员工,这些员工具有该员工类型独有的属性,例如 Doctor、Accountant、Pilot 等。这种设计避免了多个空值,因为许多员工不具备特定子类型的特殊属性。此类别中的其他示例可能是 Product 作为超类型,ManufacturingProduct 和 MaintenanceSupply 作为子类型;Animal 作为超类型,Dog 和 Cat 作为子类型;请注意,每当您尝试将面向对象的继承层次结构映射到关系数据库(例如在对象关系模型中)时,这种关系就代表了这种情况。

  • “老板”关系,如经理、董事长、总裁等,一个组织单位只能有一个老板,一个人只能是一个组织单位的老板。如果这些规则适用,那么您将拥有一对一的关系,例如一个部门的一位经理,一家公司的一位 CEO,等等。“老板”关系不仅适用于人。例如,如果只有一家商店作为公司的总部,或者只有一个城市是国家的首都,就会出现同样的关系。

  • 某些稀缺资源分配,例如,一名员工一次只能分配一辆公司汽车(例如,每个卡车司机一辆卡车,每个出租车司机一辆出租车等)。最近一位同事给我举了这个例子。

  • 婚姻(至少在一夫多妻制是非法的法律管辖区):一个人一次只能与另一个人结婚。我从一本教科书中得到这个例子,当一家公司记录其员工之间的婚姻时,该教科书将其用作 1:1 一元关系的例子。

  • Matching reservations:当一个唯一的预订被做出,然后作为两个独立的实体完成时。例如,汽车租赁系统可能会在一个实体中记录预订,然后在单独的实体中记录实际租赁。尽管这种情况也可以设计为一个实体,但将实体分开可能是有意义的,因为并非所有预订都得到满足,也不是所有租金都需要预订,而且这两种情况都很常见。

我重复我之前提出的警告,只有在没有记录历史信息的情况下,其中大多数都是 1:1 关系。因此,如果员工改变了他们在组织中的角色,或者经理负责不同的部门,或者员工被重新分配了车辆,或者某人丧偶并再婚,那么关系参与者可能会发生变化。如果数据库没有存储有关这些 1:1 关系的任何先前历史记录,那么它们仍然是合法的 1:1 关系。但是如果数据库记录了历史信息(例如为每个关系添加开始和结束日期),那么它们几乎都会变成 M​​:M 关系。

历史记录有两个值得注意的例外:首先,一些关系很少发生变化,以至于历史信息通常不会被存储。例如,大多数 IS-A 关系(例如产品类型)是不可变的;也就是说,它们永远不会改变。因此,历史记录点是没有实际意义的;这些将始终作为自然的 1:1 关系实施。其次,预订-出租关系分别存储日期,因为预订和出租是独立的事件,每个都有自己的日期。由于实体有自己的日期,而不是 1:1 关系本身具有开始日期,因此即使存储了历史信息,这些也会保持 1:1 关系。

于 2015-02-04T03:46:04.800 回答
21

由于您的措辞方式,您的问题可以以多种方式解释。回应表明了这一点。

现实世界中的数据项之间肯定存在 1:1 的关系。毫无疑问。“是”的关系通常是一对一的。汽车是交通工具。一辆车就是一辆车。一辆车可能是一辆车。有些车辆是卡车,在这种情况下,一辆车不是汽车。几个答案解决了这种解释。

但我认为你真正要问的是......当存在 1:1 关系时,是否应该拆分表?换句话说,您是否应该拥有两个包含完全相同键的表?在实践中,我们大多数人只分析主键,而不分析其他候选键,但这个问题略有不同。

1NF、2NF 和 3NF 的规范化规则从不要求将表分解(拆分)为具有相同主键的两个表。我还没有弄清楚在 BCNF、4NF 或 5NF 中放置模式是否会导致两个表具有相同的键。在我的脑海中,我猜答案是否定的。

有一个标准化级别称为 6NF。6NF 的规范化规则肯定会导致两个表具有相同的主键。6NF 与 5NF 相比具有可以完全避免 NULLS 的优势。这对某些(但不是全部)数据库设计人员很重要。我从来没有费心将模式放入 6NF。

在 6NF 中,缺失的数据可以用省略的行来表示,而不是在某些列中带有 NULL 的行。

除了规范化之外,拆分表还有其他原因。有时拆分表会带来更好的性能。使用某些数据库引擎,您可以通过对表进行分区而不是实际拆分它来获得相同的性能优势。这可以使逻辑设计易于理解,同时为数据库引擎提供加速处理所需的工具。

于 2009-02-06T10:21:41.867 回答
19

我使用它们主要有几个原因。一是数据变化率的显着差异。我的一些表可能有审计跟踪,我可以在其中跟踪以前版本的记录,如果我只关心跟踪 10 列中的 5 列的以前版本,将这 5 列拆分到一个单独的表中,上面有审计跟踪机制会更有效。另外,我可能有只写的记录(比如会计应用程序)。您不能更改美元金额或它们所用于的帐户,如果您犯了错误,则需要进行相应的记录以注销不正确的记录,然后创建更正条目。我对表有限制,强制执行它们无法更新或删除的事实,但我可能对该对象有几个可延展的属性,这些都保存在一个单独的表中,没有修改的限制。我这样做的另一次是在医疗记录应用程序中。有与访问相关的数据一旦签署就无法更改,而与访问相关的其他数据可以在签署后更改。在这种情况下,我将拆分数据并在锁定表上放置一个触发器,在注销时拒绝对锁定表的更新,但允许对医生未签署的数据进行更新。

另一位发帖人评论说 1:1 没有被规范化,在某些情况下,我不同意这一点,尤其是子类型化。假设我有一个员工表,主键是他们的 SSN(这是一个例子,让我们把关于这是否是另一个线程的好键的争论)。员工可以是不同的类型,比如临时的或永久的,如果他们是永久的,他们有更多的字段需要填写,比如办公室电话号码,只有在 type = 'Permanent' 时才应该不为空。在第 3 范式数据库中,列应该仅取决于键,即员工,但它实际上取决于员工和类型,因此 1:1 关系是完全正常的,并且在这种情况下是可取的。它还可以防止过于稀疏的表,如果我有 10 个通常填充的列,

于 2009-02-05T19:26:42.453 回答
14

我能想到的最常见的情况是当你有 BLOB 时。假设您想将大图像存储在数据库中(通常,不是存储它们的最佳方式,但有时约束使其更方便)。您通常希望 blob 位于单独的表中,以改进对非 blob 数据的查找。

于 2009-02-05T19:27:43.200 回答
9

就纯科学而言,是的,它们毫无用处。

在实际数据库中,有时将很少使用的字段保留在单独的表中很有用:使用此字段且仅使用此字段来加快查询速度;避免锁等。

于 2009-02-05T19:12:51.077 回答
9

与其使用视图来限制对字段的访问,有时将受限制的字段保存在只有特定用户可以访问的单独表中是有意义的。

于 2009-02-05T19:14:00.247 回答
8

我还可以想到您有一个使用继承的 OO 模型的情况,并且必须将继承树持久化到数据库中。

例如,您有一个类 Bird 和 Fish,它们都继承自 Animal。在您的数据库中,您可以有一个“Animal”表,其中包含 Animal 类的公共字段,Animal 表与 Bird 表具有一对一的关系,与 Fish 具有一对一的关系桌子。

在这种情况下,您不必拥有一个包含许多可空列来保存 Bird 和 Fish-properties 的 Animal 表,当记录表示一只鸟时,其中包含 Fish-data 的所有列都设置为 NULL。

相反,您在 Birds 表中有一条记录,它与 Animal 表中的记录具有一对一的关系。

于 2009-02-05T19:16:19.337 回答
8

如果您有太多信息,1-1 关系也是必要的。表中的每条记录都有记录大小限制。有时表被一分为二(在主表中最常查询的信息)只是为了记录大小不会太大。如果表很窄,数据库在查询方面也更有效。

于 2009-02-05T20:04:51.877 回答
6

这也是一种扩展已经在生产中的表的方法,其风险比“真正的”数据库更改要小。在遗留系统中看到 1:1 关系通常是一个很好的指标,表明字段是在初始设计之后添加的。

于 2009-02-05T19:16:46.967 回答
5

大多数时候,设计被认为是 1:1,直到有人问“好吧,为什么不能是 1:many”?在预料到这种常见情况时,会过早地将概念彼此分离。Person 和 Address 没有绑定得那么紧密。很多人有多个地址。等等...

通常两个独立的对象空间意味着一个或两个可以相乘(x:many)。如果两个对象是真正的、真正的 1:1,甚至在哲学上,那么它更像是一种关系。这两个“对象”实际上是一个完整对象的一部分。

于 2009-02-05T19:16:44.953 回答
5

在 SQL 中,不可能在两个表之间强制执行 1:1 关系,这对双方都是强制性的(除非表是只读的)。对于大多数实际目的,SQL 中的“1:1”关系实际上意味着 1:0|1。

无法在引用约束中支持强制基数是 SQL 的严重限制之一。“可延迟”约束并不算数,因为它们只是一种说约束有时不强制执行的方式。

于 2009-10-30T22:39:47.070 回答
4

如果您将数据与流行的 ORM 之一一起使用,您可能希望将一个表分解为多个表以匹配您的对象层次结构。

于 2009-02-05T19:13:16.660 回答
4

我发现,当我建立 1:1 的关系时,完全是出于系统原因,而不是关系原因。

例如,我发现将用户的保留方面放在 1 个表中,并将用户的用户可编辑字段放在不同的表中,可以更容易地在逻辑上编写关于这些字段的权限的规则。

但你是对的,理论上,1:1 的关系完全是人为的,几乎是一种现象。然而,从逻辑上讲,它允许程序和优化更容易抽象数据库。

于 2009-02-05T19:15:01.557 回答
3

仅在某些情况下需要的扩展信息。在遗留应用程序和编程语言(例如 RPG)中,程序是在表上编译的(因此,如果表发生更改,您必须重新编译程序)。在您必须担心表大小的情况下,标记文件也很有用。

于 2009-02-05T19:14:42.430 回答
2

大多数情况下,它更像是一种物理结构而不是逻辑结构。它通常用于对表进行垂直分区,以利用跨物理设备拆分 I/O 或与隔离不经常访问的数据或需要比同一对象上的其他属性更安全的数据相关的其他查询优化(SSN、工资等)。

规定 1-1 关系的唯一合乎逻辑的考虑是某些属性仅适用于某些实体。然而,在大多数情况下,有一种更好/更规范化的方式来通过实体提取对数据进行建模。

于 2009-02-05T19:14:28.560 回答
2

我能看到 1:1 关系的最佳原因是数据库设计的 SuperType SubType。我基于这个模型创建了一个房地产 MLS 数据结构。有五种不同的数据馈送;住宅、商业、多户家庭、酒店和土地。

我创建了一个名为属性的 SuperType,其中包含五个单独数据馈送中的每一个都共有的数据。这允许对所有数据类型进行非常快速的“简单”搜索。

我创建了五个单独的子类型,它们为五个数据馈送中的每一个存储唯一的数据元素。每个 SuperType 记录与相应的 SubType 记录具有 1:1 的关系。

如果客户想要进行详细搜索,他们必须选择 Super-Sub 类型,例如 PropertyResidential。

于 2009-10-31T01:07:09.683 回答
1

在我看来,1:1 的关系映射了 RDBMS 上的类继承。有一个包含公共属性的表A,即子类状态每个继承的类状态都映射到RDBMS 上,表B 与A 表具有1:1 的关系,包含专门的属性。表 namend A 还包含一个表示“转换”功能的“类型”字段

再见马里奥

于 2009-08-12T13:36:10.320 回答
1

如果有任何显着的性能优势,您可以创建一个一对一的关系表。您可以将很少使用的字段放入单独的表中。

于 2015-09-17T02:29:31.863 回答
0

如果您要进行标准化,那么 1:1 的关系就没有任何意义,因为任何 1:1 的关系都将保存在同一张表中。

但在现实世界中,它通常是不同的。您可能希望分解数据以匹配您的应用程序界面。

于 2009-02-05T19:16:21.537 回答
0

可能如果您的数据库中有某种类型的对象。

假设在表 T1 中,您有 C1、C2、C3 列……具有一对一的关系。没关系,它是标准化的形式。现在说在表 T2 中,您有列 C1、C2、C3、……(名称可能不同,但说类型和角色相同)也具有一对一的关系。T2 可以,原因与 T1 相同。

然而,在这种情况下,我认为适合单独的表 T3,包含 C1、C2、C3……以及从 T1 到 T3 以及从 T2 到 T3 的一对一关系。如果存在另一个表,我什至更认为合适,其中已经存在一个对多个 C1、C2、C3 ......比如说从表 A 到表 B 中的多行。然后,你使用 B 而不是 T3,并且有从 T1 到 B 的一对一关系,从 T2 到 B 相同,从 A 到 B 仍然是相同的一对多关系。

我相信规范化不同意这一点,这可能是一个想法:识别对象类型并将相同类型的对象移动到自己的存储池,使用某些表中的一对一关系,以及一对多的关系来自其他一些表的关系。

于 2013-08-23T01:24:14.157 回答
0

出于安全目的,这没有必要很好,但有更好的方法来执行安全检查。想象一下,你创造了一把只能打开一扇门的钥匙。如果钥匙可以打开任何其他门,您应该响铃。本质上,您可以拥有“CitizenTable”和“VotingTable”。公民一号投票给存储在投票表中的候选人一号。如果公民一再次出现在投票表中,那么他们应该是一个警报。请注意,这是一对一的关系,因为我们不是指候选人字段,而是指投票表和公民表。

例子:

 Citizen Table
 id = 1, citizen_name = "EvryBod"
 id = 2, citizen_name = "Lesly"
 id = 3, citizen_name = "Wasserman"

 Candidate Table
 id = 1, citizen_id = 1, candidate_name = "Bern Nie"
 id = 2, citizen_id = 2, candidate_name = "Bern Nie"
 id = 3, citizen_id = 3, candidate_name = "Hill Arry"

那么,如果我们看到投票表是这样的:

 Voting Table
 id = 1, citizen_id = 1, candidate_name = "Bern Nie"
 id = 2, citizen_id = 2, candidate_name = "Bern Nie"
 id = 3, citizen_id = 3, candidate_name = "Hill Arry"
 id = 4, citizen_id = 3, candidate_name = "Hill Arry"
 id = 5, citizen_id = 3, candidate_name = "Hill Arry"

可以说,3号公民是个骗子,着火了,骗了聂伯尔尼。只是一个例子。

于 2016-08-05T23:37:32.757 回答
0

当您处理来自第三方产品的数据库时,您可能不想更改他们的数据库以防止紧密耦合。但您的数据可能与他们的数据 1:1 对应

于 2019-09-19T07:34:54.087 回答
-4

任何地方都有两个完全独立的实体共享一对一的关系。应该有很多例子:

人 <-> 牙医(它的 1:N,所以它错了!)

人<->医生(它的1:N,所以它也是错误的!)

人 <-> 配偶(它的 1:0|1,所以它大多是错误的!)

编辑:是的,这些都是非常糟糕的例子,特别是如果我一直在寻找 1:1,而不是两边的 0 或 1。我想我的大脑发错了:-)

所以,我会再试一次。事实证明,经过一番思考,你可以拥有两个必须(就软件而言)一直在一起的独立实体的唯一方法是让它们在更高的分类中一起存在。然后,当且仅当您陷入较低的分解时,事物是并且应该是分开的,但在较高的层次上,它们不能没有彼此。上下文,然后是关键。

对于医学数据库,您可能希望存储有关身体特定区域的不同信息,将它们作为一个单独的实体保存。在那种情况下,一个病人只有一个头,他们需要它,否则他们就不是病人。(他们也有一颗心脏,以及许多其他必要的单一器官)。例如,如果您对跟踪手术感兴趣,那么每个区域都应该是一个独特的独立实体。

在生产/库存系统中,如果您正在跟踪车辆的组装,那么您当然希望以不同于车身的方式观察发动机的进展,但存在一对一的关系。护理必须有一个引擎,而且只有一个(否则它就不再是“汽车”了)。一个引擎只属于一辆车。

在每种情况下,您都可以将单独的实体生成为一个大记录,但考虑到分解的程度,那将是错误的。在这些特定的上下文中,它们是真正独立的实体,尽管它们在更高的层次上可能不会如此。

保罗。

于 2009-02-05T21:08:11.093 回答