有没有什么时候使用数据库1:1的关系是有意义的?

我前几天想到了正常化,而且我想到了一个数据库中应该有1:1关系的时候。

名称:SSN? 我会让他们在同一个表PersonID:AddressID? 再次,同一张桌子。

我可以拿出一个1:多个或多个:许多(与适当的中间表),但从来没有1:1。

我错过了什么明显的?

1:1关系通常表示由于某种原因,您已经划分了较大的实体。 通常,这是因为物理架构中的性能原因,但是也可能发生在逻辑端,如果大部分数据同时被预期为“未知”(在这种情况下,您有一个1:0或1:1,但没有更多)。

作为逻辑分区的一个例子:您有关于员工的数据,但是当且仅当他们select了健康覆盖时,需要收集更多的数据。 我会将有关健康覆盖的人口统计数据保存在一个不同的表格中,以便更轻松地进行安全分区,并避免在与保险无关的查询中引用数据。

物理分区的一个例子是在多台服务器上托pipe相同的数据。 我可能会将健康保险人口统计数据保存在另一个州(例如人力资源办公室),而主数据库只能通过链接的服务器链接到该数据库…避免将敏感数据复制到其他位置, (假设在这里很less)需要它的查询。

物理分区您需要具有较大实体的一致子集的查询非常有用。

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

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

我的博客条目。

稀疏。 数据关系在技术上可以是1:1,但是对于每一行都不必存在对应的行。 所以,如果你有两千万行,并且只有0.5%的值存在一些值,那么如果你把这些列放到一个可以稀疏填充的表中,空间节省是巨大的。

我主要使用它们有几个原因。 一是数据变化率有显着差异。 我的一些表可能有跟踪以前版本的logging的审计跟踪,如果我只关心跟踪以前版本的5列(10列),将这5列分割到一个单独的表上,使用审计跟踪机制更有效。 另外,我可能有只写的logging(比如说一个会计应用程序)。 如果您犯了一个错误,您不能更改美元金额或账户,那么您需要做出相应的logging来调整不正确的logging,然后创build一个更正条目。 我在表上强制约束它们不能被更新或删除,但是我可能有一些属性是可延展的,那些属性保存在一个单独的表中,而不受修改的限制。 另一次我做的是在医疗logging应用程序。 有关于访问的数据,一旦签名就无法更改,其他与访问有关的数据可以在签退后更改。 在这种情况下,我将拆分数据,并在locking表上放置一个触发器,拒绝签名时对locking表的更新,但允许更新医生没有注销的数据。

另一个海报评论1:1没有正常化,我不同意在某些情况下,特别是分类。 假设我有一个雇员表,主键是他们的SSN(这是一个例子,让我们保存这个关键是否是另一个线程的好钥匙)。 员工可以是不同的types,比如说临时或永久的,如果他们是永久性的,他们有更多的填写字段,比如办公室的电话号码,如果types=“永久”,则只能是空的。 在第三范式数据库中,列仅依赖于关键字,即员工,但实际上取决于员工和types,所以1:1关系是完全正常的,在这种情况下是可取的。 它也可以防止过度稀疏的表,如果我有10个通常填充的列,但只有20个额外的列只对某些types。

你的问题可以用几种方式解释,因为你的措辞。 答案显示了这一点。

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

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

1NF,2NF和3NF的规范化规则不需要将表分解(拆分)为具有相同主键的两个表。 我还没有计算出在BCNF,4NF或5NF架构中是否可以使用相同的密钥生成两个表。 关于我的头顶,我会猜测答案是否定的。

有一个称为6NF的标准化水平。 6NF的规范化规则肯定会导致两个表具有相同的主键。 6NF比5NF有优势,NULLS可以完全避免。 这对于一些(但不是全部)数据库devise者来说很重要。 我从来没有打算把架构放入6NF。

在6NF中,缺less的数据可以用一个省略的行来表示,而不是在某一列用NULL来表示。

除了正常化之外,还有其他的原因来分割表格。 有时拆分表会导致更好的性能。 使用一些数据库引擎,您可以通过分区表来获得相同的性能优势,而不是实际分割它。 这可以使逻辑devise易于理解,同时为数据库引擎提供加速所需的工具。

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

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

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

  • “Is-A”或超types/子types或inheritance/分类关系 :这个类别是当一个实体是另一个实体的特定types时。 例如,可能有一个雇员实体的属性适用于所有雇员,然后是不同的实体,以指示具有该雇员types特有的属性的特定types的雇员,例如医生,会计师,飞行员等。这种devise避免了多个空值许多员工不具备特定子types的特定属性。 此类别中的其他示例可以是Product作为超types,ManufacturingProduct和MaintenanceSupply作为子types; 动物为超型,狗和猫为亚型; 等等。请注意,每当您试图将面向对象的inheritance层次结构映射到关系数据库(例如在对象关系模型中)时,这就是表示这种情况的那种关系。

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

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

  • 婚姻 (至less在一夫多妻制是非法的司法辖区):一个人一次只能与另一个人结婚。 当一家公司logging员工之间的婚姻时,我从一本教科书中得到了这个例子,这本书是以1:1一元关系为例。

  • 匹配保留 :当一个唯一的保留,然后作为两个单独的实体完成。 例如,汽车租赁系统可以在一个实体中logging保留,然后在单独的实体中logging实际的租赁。 虽然这样的情况也可以被devise为一个实体,但是由于并不是所有的保留都得到满足,并不是所有的保留都是需要保留的,所以将这些实体分开是有意义的,这两种情况都是非常普遍的。

我再重复一下前面提到的,只有在没有logging历史信息的情况下,这些关系才是1:1的关系。 所以,如果一个员工改变了他们在一个组织中的angular色,或者一个经理负责了一个不同的部门,或者一个员工被重新分配了一辆车,或者某个人丧偶和再婚,那么关系参与者就可以改变。 如果数据库不存储关于这些1:1关系的任何以前的历史logging,则它们保持合法的1:1关系。 但是如果数据库logging了历史信息(比如添加每个关系的开始和结束date),那么他们几乎全部变成M:M关系。

历史笔记有两个明显的例外:首先,一些关系变化很less,通常不会存储历史信息。 例如,大多数IS-A关系(例如产品types)是不可变的; 也就是说,他们永远不会改变。 因此,历史logging是有争议的; 这些将始终作为自然的1:1关系来实施。 其次,预订 – 出租关系存储单独的date,因为预订和租赁是独立的事件,每个都有自己的date。 由于实体具有自己的date,而不是1:1关系本身具有开始date,所以即使历史信息被存储,这些关系也将保持1:1关系。

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

在真正的数据库中,将一个很less使用的字段保存在一个单独的表中有时是有用的:使用这个字段和只有这个字段来加速查询; 避免锁等

而不是使用视图来限制对字段的访问,有时将受限字段保留在只有特定用户才能访问的单独表中。

我也可以想到你有一个使用inheritance的OO模型的情况,并且inheritance树必须被持久化到DB。

例如,你有一个类动物鸟类和鱼类。 在你的数据库中,你可以有一个“Animal”表,它包含Animal类的公共字段,Animal表与Bird表有一对一的关系,与Fish有一对一的关系表。

在这种情况下,您不必拥有一个包含大量可空列的动物表来存放Bird和Fish属性,其中包含Fish-数据的所有列在logging代表鸟时都设置为NULL。

相反,您在Bird表中有一个与Animal表中的logging具有一对一关系的logging。

如果你有太多的信息,1-1关系也是必要的。 表格中的每个logging都有一个logging大小限制。 有时候,表被分成两部分(主表中最常见的信息),以便logging大小不会太大。 数据库在查询表格是否很窄时也更有效率。

这也是扩展已经投入生产的表的一种方式,其风险比“真正的”数据库更改更less。 在传统系统中看到1:1的关系通常是在初始devise之后添加字段的一个很好的指标。

如果您将数据与stream行的ORM之一一起使用,则可能需要将表分成多个表以匹配对象层次结构。

我发现,当我做一对一的关系时,完全是为了一个系统的原因,而不是一个关系的原因。

例如,我发现将用户的保留方面放在一个表中,并将用户的用户可编辑字段置于不同的表中,这使得在逻辑上写这些有关这些字段的权限的规则要容易得多。

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

大多数时候,devise被认为是1:1,直到有人问“为什么不能是1:多”? 过早地将概念彼此分离是为了预期这种常见的情况。 人和地址不太紧密。 很多人有多个地址。 等等…

通常两个单独的对象空间意味着一个或两个可以相乘(X:很多)。 如果两个对象确实是真正的1:1,甚至是哲学上的,那么它就更像是一种关系。 这两个“物体”实际上是整个物体的一部分。

扩展的信息只在某些情况下需要。 在传统的应用程序和编程语言(如RPG)中,程序在表格上进行编译(所以如果表格发生变化,您必须重新编译程序)。 在需要担心表格大小的情况下,沿着文件标记也是有用的。

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

在参考约束中无法支持强制基数是SQL严重的限制之一。 “可延迟的”约束并不是真正的数量,因为它们只是说约束没有被强制执行的一种方式。

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

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

我可以看到1:1关系的最佳理由是数据库devise的SuperType子types。 我创build了一个基于此模型的房地产MLS数据结构。 有五种不同的数据input; 住宅,商业,多户,酒店和土地。

我创build了一个名为“属性”的SuperType,其中包含五个单独的数据源中每个数据源所共有的数据。 这就允许在所有数据types中进行非常快速的“简单”search。

我创build了五个独立的子types,为五个数据源中的每一个存储唯一的数据元素。 每个SuperTypelogging与适当的SubTypelogging具有1:1的关系。

如果客户想要详细search,他们必须select一个Super-Subtypes,例如PropertyResidential。

在我看来,1:1关系映射RDBMS上的类inheritance。 有一个包含公共属性的表A,即partent类的状态每个inheritance的类的状态都映射到RDBMS上,表B与表A有1:1的关系,包含专门的属性。 表格名称A还包含表示“铸造”function的“types”字段

再见马里奥

1:1关系如果进入正常化状态并不合理,因为任何1:1的关系都会保存在同一个表中。

但在现实世界中,情况往往不同。 您可能希望打破您的数据以匹配您的应用程序界面。

可能的话,如果你在你的数据库中有某种types的对象。

在表T1中,你有C1,C2,C3 …这样的列,它们是一对一的关系。 没关系,这是正常化的forms。 现在在表T2中说,你有C1,C2,C3,…(名字可能不同,但是说types和angular色是一样的)也是一对一的关系。 T2和T1的原因相同。

然而,在这种情况下,我看到一个单独的表格T3,C1,C2,C3 …和从T1到T3以及从T2到T3的一对一关系。 如果还有另外一个表格,我已经看到一个合适的expression式,那里已经存在一个表C1,C2,C3 ……从表A到表B的多行。然后,用T3代替T3,从T1到B一对一的关系,从T2到B也是一样的,从A到B仍然是一对多的关系。

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

如果有任何显着的性能优势,您可以创build一对一的关系表。 您可以将罕用字段放在单独的表格中。

对于安全目的来说没有必要,但是有更好的方法来执行安全检查。 试想一下,你创build一个只能打开一扇门的钥匙。 如果钥匙可以打开任何其他的门,你应该打开闹钟。 本质上,你可以有“CitizenTable”和“VotingTable”。 公民对投票表中存储的候选人一票。 如果公民再次出现在投票表中,那么他们应该是一个警报。 build议,这是一对一的关系,因为我们不是指候选人领域,而是指投票表和公民表。

例:

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号公民是欺骗伯恩斯聂的骗子裤子。 只是一个例子。

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

人< – >牙医(其1:N,所以错了!)

人 – – 医生(它的1:N,所以也是错的!)

个人配偶(其1:0 | 1,所以它大多是错的!)

编辑:是的,这些是非常糟糕的例子,特别是如果我一直在寻找1:1,而不是0或1任何一方。 我想我的大脑是错误的: – )

所以,我会再试一次。 事实certificate,经过一番思考,唯一可以让两个单独的实体(就软件而言)一直在一起的唯一方式就是让它们在更高的分类中一起存在。 那么,当且仅当你陷入较低的分解状态时,事物是和应该是分开的,但是在更高的层次上,它们是不能彼此独立生存的。 上下文是关键。

对于医疗数据库,您可能需要存储有关身体特定区域的不同信息,并将其作为单独的实体保存。 在这种情况下,病人只有一个头,他们需要拥有它,或者他们不是病人。 (他们也有一颗心,还有一些其他必要的单一器官)。 例如,如果您有兴趣跟踪手术,那么每个区域应该是一个独特的独立实体。

在生产/库存系统中,如果您正在跟踪车辆组装,那么您肯定希望看到发动机进展与车身不同,但是存在一对一的关系。 小心必须有一个引擎,只有一个(或不会是一个'车'了)。 一台发动机只属于一辆车。

在每一种情况下,您都可以将单独的实体作为一个大logging生成,但是考虑到分解的层次,那将是错误的。 在这些具体情况下,它们是真正独立的实体,尽pipe它们可能不会在更高的层次上出现。

保罗。