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

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

42617 次浏览

不经常。

如果需要实现某些安全性,您可能会发现一些好处——这样一些用户可以看到某些列(表1) ,而不能看到其他列(表2)。.

当然,有些数据库(Oracle)允许您在同一个表中执行这种安全性,但有些数据库可能不允许。

If data in one table is related to, but does not 'belong' to the entity described by the other, then that's a candidate to keep it separate.

This could provide advantages in future, if the separate data needs to be related to some other entity, also.

If you place two one-to-one tables in one, its likely you'll have semantics issue. For example, if every device has one remote controller, it doesn't sound quite good to place the device and the remote controller with their bunch of characteristics in one table. You might even have to spend time figuring out if a certain attribute belongs to the device or the remote controller.

可能会有这样的情况,你的栏目中有一半会长时间空着,或者永远不会被填满。例如,一辆汽车可能只有一辆带有许多特征的拖车,也可能没有。因此,您将拥有许多未使用的属性。

如果您的表有20个属性,而其中只有4个是偶尔使用的,那么为了解决性能问题,将表分成2个表是有意义的。

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

你指的是数据库规范化。在我维护的应用程序中,我可以想到的一个例子是 Items。该应用程序允许用户销售许多不同类型的商品(如 InventoryItems、 NonInventoryItems、 ServiceItems 等等)。.).虽然我可以在一个 Items 表中存储每个项目所需的所有字段,但是维护一个包含所有项目通用字段的基 Item 表,然后为每个项目类型分离表(例如,Inventory,NonInventory,等等)要容易得多其中包含仅特定于该项类型的字段。然后,项目表将拥有它所表示的特定项目类型的外键。特定项表与基项表之间的关系将是一对一的。

下面是一篇关于标准化的文章。

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

对于所有的设计问题,答案都是“视情况而定”

几乎没有什么需要考虑的:

  • 表会有多大(无论是字段还是行) ?从维护和编程的角度来看,将用户名、密码和其他不太常用的数据放在一起是不方便的

  • 组合表中具有约束的字段随着时间的推移可能变得难以管理。例如,如果一个触发器需要触发一个特定的字段,那么无论该字段是否受到影响,对表的每次更新都会触发该触发器。

  • 你有多大把握你们的关系会是1:1? 正如 这个的问题所指出的,事情会很快变得复杂。

The most sensible time to use this would be if there were two separate concepts that would only ever relate in this way. For example, a Car can only have one current Driver, and the Driver can only drive one car at a time - so the relationship between the concepts of Car and Driver would be 1 to 1. I accept that this is contrived example to demonstrate the point.

另一个原因是,您希望以不同的方式专门化一个概念。如果您有一个 Person 表,并且想要添加不同类型 Person 的概念,例如 Employee、 Customer、 Shareholder ——每个类型都需要不同的数据集。它们之间类似的数据将位于 Person 表中,专家信息将位于 Customer、 Shareholder、 Employee 的特定表中。

Some database engines struggle to efficiently add a new column to a very large table (many rows) and I have seen extension-tables used to contain the new column, rather than the new column being added to the original table. This is one of the more suspect uses of additional tables.

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

1比0. . 1

  • The "1 to 0..1" between super and sub-classes is used as a part of "all classes in separate tables" strategy for 实现继承.

  • 1比0。可以在一个表中用“0”表示。.1“由 NULL 可用字段覆盖的部分。但是,如果关系是 差不多吧“1到0”,只有几行“1到1”,则将“0”分开。将.1“部分放到单独的表中可能会节省一些存储(和缓存性能)方面的好处。有些数据库在存储 NULL 方面比其他数据库更节省,因此这种策略可行的“分界点”可能有很大的不同。

1 to 1

  • The real "1 to 1" vertically partitions the data, which may have implications for caching. Databases typically implement caches at the page level, not at the level of individual fields, so even if you select only a few fields from a row, typically the whole page that row belongs to will be cached. If a row is very wide and the selected fields relatively narrow, you'll end-up caching a lot of information you don't actually need. In a situation like that, it may be useful to vertically partition the data, so only the narrower, more frequently used portion or rows gets cached, so more of them can fit into the cache, making the cache effectively "larger".

  • 垂直分区的另一个用途是改变锁定行为: 数据库通常不能锁定单个字段的级别,只能锁定整个行。通过分割行,您只允许锁在其一半上发生。

  • Triggers are also typically table-specific. While you can theoretically have just one table and have the trigger ignore the "wrong half" of the row, some databases may impose additional limits on what a trigger can and cannot do that could make this impractical. For example, Oracle doesn't let you modify the mutating table - by having separate tables, only one of them may be mutating so you can still modify the other one from your trigger.

  • 单独的表可能允许更细粒度的安全性。

在大多数情况下,这些注意事项是不相关的,因此在大多数情况下,您应该考虑将“1到1”表合并到单个表中。

参见: 为什么在数据库设计中使用1对1的关系?

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

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

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

    • 个人实体,在同一公司内为会计、工程师、销售人员设有单独的实体。
    • 项目实体,包含 Widget、 RawMaterials、 FinishedGood 等的单独实体。
    • Car entity, with separate entities for Truck, Sedan, etc.

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

  2. “老板”的关系。当一个人是某个组织单位(部门、公司等)的独一无二的老板、经理或主管时。当一个组织单位只允许有一个老板时,那么代表老板的个人实体和组织单位实体之间就存在1:1的关系。

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

当「实体 A 」有多个「实体 B 」而「实体 B 」只有1个「实体 A 」时 还有 “实体 A”只有1个当前的“实体 B”,而“实体 B”只有1个“实体 A”。

例如,一辆汽车只能有一个当前的驱动程序,并且驱动程序一次只能驱动一辆汽车-所以 Car 和 Driver 的概念之间的关系是1比1。- 我借用了这个例子从@史蒂夫芬顿的答案

一个司机可以驾驶多辆车,只是不能在同一时间。因此,Car 和 Driver 实体是1对多或多对多。但是如果我们需要知道当前驱动程序是谁,那么我们还需要1:1的关系。

首先,我认为这是一个建模和定义什么组成一个单独的实体的问题。假设您有一个且只有一个 addresscustomers。当然,您可以在一个表 customer中实现所有内容,但是如果将来您允许他拥有2个或更多地址,那么您将需要重构该地址(这不是问题,但需要有意识地做出决定)。

我还可以想到一个其他答案中没有提到的有趣案例,在这个案例中,分割表格可能是有用的:

再想象一下,您有一个 customers,每个 address一个,但是这一次它是可选的有一个地址。当然,您可以将其实现为一组 NULL-able 列,例如 ZIP,state,street。但是假设给定你 address0和 addressstate不是可选的,而 ZIP是。如何在单个表中建模?您可以对 customer表使用约束,但是划分另一个表并使 foreign _ key 为 NULLable 要容易得多。这样,您的模型更加明确地表示 address1 address是可选的,而 ZIP是该实体的可选属性。

My 2 cents.

我工作的地方,我们都在开发一个大型应用程序,一切都是一个模块。例如,我们有一个 users表,我们有一个为用户添加 facebook 详细信息的模块,另一个为用户添加 twitter 详细信息的模块。我们可以决定拔掉其中一个模块的插头,并从应用程序中删除它的所有功能。在这种情况下,每个模块向全局 users表添加自己的表,它们之间的关系为1:1,如下所示:

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

另一个用例可能是超过了数据库表中的最大列数。然后您可以使用 OneToOne 加入另一个表

使用一对一关系的主要时间是涉及到继承的时候。

下面,一个人可以是员工和/或客户。员工和客户继承人员属性。这样做的好处是,如果一个人是工作人员和客户,他们的详细信息只存储一次,在通用的人员表中。子表具有特定于员工和客户的详细信息。

one-to-one relationship ERD