什么时候应该使用一对一关系?


91

很抱歉这个菜鸟问题,但是是否真的需要对数据库中的表使用一对一关系?您可以在一个表中实现所有必需的字段。即使数据变得很大,您也可以在SELECT语句中枚举所需的列名,而不必使用SELECT *。您何时真正需要这种分离?

Answers:


104

1至0..1

  • 父类和子类之间的“ 1至0..1”用作实现继承的“单独表中的所有类”策略的一部分。

  • 可以在单个表中表示“ 1到0..1”,其中“ 0..1”部分覆盖可空字段。但是,如果关系主要是“ 1到0”而只有几行“ 1到1”,则将“ 0..1”部分拆分为单独的表可能会节省一些存储(和缓存性能)的好处。一些数据库在存储NULL方面比其他数据库更为节俭,因此使该策略可行的“临界点”可能会有很大差异。

一对一

  • 实际的“ 1对1”会垂直分割数据,这可能会影响缓存。数据库通常在页面级别而不是在单个字段级别上实现缓存,因此,即使您仅从一行中选择了几个字段,通常也将缓存该行所属的整个页面。如果一行很宽,并且所选字段相对较窄,那么您最终将缓存很多实际上不需要的信息。在这种情况下,垂直分区数据可能很有用,因此缓存较窄,更频繁使用的部分或行,以便将更多的部分或行放入缓存中,从而使缓存有效地“更大”。

  • 垂直分区的另一种用途是更改锁定行为:数据库通常无法锁定单个字段的级别,只能锁定整个行。通过拆分行,您只允许在锁的一半上进行锁定。

  • 触发器通常也是特定于表的。从理论上讲,您只能有一个表,而触发器却忽略了该行的“错误的一半”,但是某些数据库可能会对触发器可以做什么和不可以做什么施加了额外的限制,这可能使这变得不切实际。例如,Oracle不允许您修改变异表-通过具有单独的表,只有其中一个可以变异,因此您仍然可以从触发器中修改另一个。

  • 单独的表可以提供更精细的安全性。

这些注意事项在大多数情况下都是无关紧要的,因此在大多数情况下,您应考虑将“ 1对1”表合并为一个表。


20

如果一个表中的数据与另一个表所描述的实体相关但不“属于”另一个表所描述的实体,则可以将其分开。

如果单独的数据也需要与某些其他实体相关联,则这可能会在将来提供优势。


19

如果将两个一对一的表放在一个表中,很可能会遇到语义问题。例如,如果每个设备都具有一个遥控器,那么将设​​备和遥控器及其一系列特性放在一张表中听起来并不好。您甚至可能不得不花时间弄清楚某个属性是属于设备还是遥控器。

在某些情况下,您的一半列可能会长时间空着,或者永远不会被填充。例如,一辆汽车可能有一个带有很多特征的拖车,或者可能没有。因此,您将有许多未使用的属性。

如果您的表有20个属性,并且偶尔只使用其中的4个,则出于性能问题,将表分为2个表是有意义的。

在这种情况下,将所有内容都放在一个表中是不好的。此外,处理具有45列的表并不容易!


17

我的2美分。

我在一个所有人都在一个大型应用程序中进行开发的地方工作,并且所有内容都是一个模块。例如,我们有一个users表,我们有一个为用户添加Facebook详细信息的模块,另一个向用户添加Twitter详细信息的模块。我们可以决定拔出其中一个模块,并从我们的应用程序中删除其所有功能。在这种情况下,每个模块都将自己的表以1:1关系添加到全局users表,如下所示:

create table users ( id int primary key, ...);
create table users_fbdata ( id int primary key, ..., constraint users foreighn key ...)
create table users_twdata ( id int primary key, ..., constraint users foreighn key ...)

13

最明智的使用时间是,如果有两个单独的概念仅以这种方式联系在一起。例如,一辆汽车只能有一个当前的驾驶员,而驾驶员一次只能驾驶一辆汽车-因此,汽车和驾驶员的概念之间的关系为1比1。点。

另一个原因是您想以不同的方式来专门化一个概念。如果您有一个Person表,并想添加不同类型的Person(例如Employee,Customer,Shareholder)的概念,则每个人都需要不同的数据集。它们之间相似的数据将在“人员”表上,专家信息将在“客户”,“股东”,“雇员”的特定表上。

一些数据库引擎难以有效地将新列添加到非常大的表(许多行)中,并且我已经看到扩展表用于包含新列,而不是将新列添加到原始表中。这是附加表的更可疑用法之一。

您可能还决定将单个概念的数据划分为两个不同的表,以解决性能或可读性问题,但这是一个相当特殊的情况,如果您是从头开始的话-这些问题将在以后显示。


5

不经常。

如果您需要实现某些安全性,则可能会发现一些好处-因此某些用户可以看到某些列(table1),而看不到其他列(table2)。

当然,某些数据库(Oracle)允许您在同一张表中执行这种安全性,而另一些数据库则不允许。


5

您指的是数据库规范化。我可以在我维护的应用程序中想到的一个示例是Items。该应用程序允许用户出售许多不同类型的项目(即InventoryItems,NonInventoryItems,ServiceItems等)。虽然我可以将每个物料所需的所有字段存储在一个物料表中,但要维护一个基本物料表要容易得多,该物料表包含所有物料共有的字段,然后针对每种物料类型(例如,库存,非库存,等。)包含仅适用于该项目类型的字段。然后,项目表将有一个外键指向它表示的特定项目类型。特定项目表和基础项目表之间的关系将是一对一的。

下面是有关规范化的文章。

http://support.microsoft.com/kb/283878


3

与所有设计问题一样,答案是“取决于情况”。

有几点注意事项:

  • 该表将变大(在字段和行方面)?从维护和编程的角度来看,将用户名,密码和其他不常用的数据保存在一起可能很不方便

  • 随着时间的推移,组合表中具有约束的字段可能变得很麻烦。例如,如果某个触发器需要为特定字段触发,那么无论该字段是否受到影响,对于表的每次更新都会发生这种情况。

  • 您如何确定该关系将为1:1?正如这个问题所指出的,事情很快就会变得复杂。


3

另一个用例可以是:您可以从某些来源导入数据并每天进行更新,例如,有关书籍的信息。然后,您自己添加有关某些书籍的数据。然后,有必要将导入的数据而不是您自己的数据放在另一个表中。


2

在实践中,我通常会遇到两种一般的1:1关系:

  1. IS-A关系,也称为超类型/子类型关系。这是当一种实体实际上是另一种实体(EntityA IS A EntityB)的类型时。例子:

    • 个人实体,在同一公司内具有会计,工程师,销售员的不同实体。
    • 项目实体,具有Widget,RawMaterial,FinishedGood等独立实体。
    • 汽车实体,以及用于卡车,轿车等的单独实体。

    在所有这些情况下,超类型实体(例如Person,Item或Car)将具有所有子类型共有的属性,并且子类型实体将具有每个子类型唯一的属性。子类型的主键将与父类型的主键相同。

  2. “老板”关系。这是一个人是组织单位(部门,公司等)的唯一老板或经理或主管的情况。当只允许一个老板担任组织单位时,代表老板的人实体与组织单位实体之间存在1:1的关系。


1
我喜欢第二个例子。您可以具有实体“部门”和实体“雇员”。在一个部门中,您有很多员工,而一个员工只能在一个部门中工作。这是1:n。雇员可以是一个部门的主管-只能是一个部门,并且该部门只有一名主管。因此,您最终得到了两个表,它们具有两个关系-1:n和1:1。
cezar

2

首先,我认为这是一个建模和定义组成独立实体的问题。假设您只有customers一个,只有一个address。当然,您可以在一个表中实现所有功能customer,但是如果将来允许他使用2个或更多地址,则需要对其进行重构(不是问题,而是要有意识地做出决定)。

我还可以想到一个有趣的案例,在其他答案中没有提到,在这种情况下,拆分表可能很有用:

再次想像,您每个人customers只有一个address,但是这次有一个地址是可选的。当然,您可以将其实现为一堆NULL可用的列,例如ZIP,state,street。但是,假设您确实有一个地址,则状态不是可选的,而ZIP是。如何在单个表中建模?您可以在customer表上使用约束,但是将其划分到另一个表中并使其foreign_key可为空则要容易得多。这样一来,您的模型就可以更明确地说明该实体 address是可选的,而则该实体是该实体ZIP的可选属性。


0

在我编程的时候,我仅在一种情况下遇到过这种情况。在相同的两个实体(“实体A”和“实体B”)之间存在一对多和一对一关系时。

当“实体A”具有多个“实体B”且“实体B”仅具有1个“实体A”且“实体A”仅具有1个当前“实体B”且“实体B”仅具有1个“实体A”时。

例如,一辆汽车只能有一个当前的驾驶员,而驾驶员一次只能驾驶一辆汽车-因此,汽车和驾驶员的概念之间的关系为1:1。-我从@Steve Fenton的答案中借用了这个示例

驾驶员可以同时驾驶多辆汽车的地方。因此,汽车和驾驶员实体是一对多或多对多的。但是,如果我们需要知道当前驱动程序是谁,那么我们还需要一对一关系。


0

另一个用例可能是如果超出了数据库表中的最大列数。然后您可以使用OneToOne联接另一个表

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.