3

当我进行数据库建模时,我从不使用弱实体,到目前为止一切似乎都很好。我通常通过给每个实体一个主(自动生成)键来忽略整个问题。

但是,我遇到了一些帖子,其中提到如果某些实体的存在完全依赖于其他实体,则它们应该是弱的。

但另一方面,有些人将弱实体称为不具备足够属性来形成主键的集合。好吧,这意味着我的数据库中的所有实体在我给它们自动递增键之前一开始都很弱。

有人可以概述弱实体的重要性以及不使用它们的后果是什么?为什么我们不给每个实体一个自动生成的主键并让它变得强大呢?

更新:

也许有人可以解释为什么弱实体应该由父实体的主键+标识符来标识,而不是创建代理键并使用外键将其与父实体相关联(更新和删除时的级联更改)?

4

3 回答 3

2

以包含多个订单行项目的订单为例。弱实体将是存储在自己的表中的各个行项目。它们的主键可以是订单的主键,加上一个简单的整数(例如 1、2、3,仅在订单内是唯一的)。因此,它们实际上并没有自己的主键作为唯一编号列,它们的键跨越两列,并且只有这种方式是唯一的。

如果订单被删除,则应删除订单行项目 - 它们单独存在没有意义。正是这种联系使它们变得脆弱——一件事被删除应该删除另一件事。

如果您为每个订单项目提供自己的主键,您仍然需要将它们关联回订单项目,这意味着为订单项目放置一个外键,或者拥有一个交叉引用表。(您可能还需要知道订单中的行项目编号,这意味着添加一个简单的整数列......此时您已经添加了足够多的键,没有自动生成的键。)对于设计模式在拥有的子项目中,这些选择中的任何一个都有点矫枉过正。

使用复杂主键还强制了订单和订单项之间的关系,因为此架构不允许您不能将订单项分配给多个订单。

另一个考虑因素是您可以根据订单项目主键对订单和订单行项目进行分片,因为两个表都有该键。(基于主键的分片通常比常规列更容易。)


分层遏制并不总是您想要的。但是,这是一种常见的模式,很高兴能清楚地了解它,在这种情况下可以使用复合键。在这里,使用带有订单项的订单项作为子项(即包含),我们不仅是说订单项相对于订单是一对多的,而且订单项是拥有的并且不独立于订单而存在 -该行项目组成以创建单个订单对象。

为此,我们明确不会为(所有)订单项(作为一个组)管理单独的键空间,而是借用和扩展订单的键空间。我们没有要求系统为行项目维护一个单独的键空间,并手动(即不太正式地)维护与订单的外键关系,并且还单独维护一个整数行项目(与订单外引用),我们可以要求系统确保整个组合键的唯一性,其中包括订单中的行项目号。

当然,您将无法添加与订单无关的订单项,但此外,使用复合子键,您也无法添加与另一个重叠的订单项(例如不会让您为同一订单添加两个订单项 #3)。

这迫使订单项的生产者和消费者将它们视为包含在订单中和订单的一部分,而不是作为独立的项目,或者换句话说,通过订单来引用订单项,或者换句话说, 通过引用其中一个订单项来“免费”获得对订单的引用。(并且由于您还可以将顺序作为此类外键的一部分引用,因此您也可以单独使用复合外键的该顺序部分来分组或加入。)

于 2013-01-06T16:35:46.907 回答
1

我最近参与了一个项目,该项目必须管理大量用于湖泊读数的数据样本。在这个项目中,我们有类似于以下的表格,其中records是按位置和上传者收集的湖泊读数,并samples包含实际的湖泊读数——比如温度和强度。

CREATE TABLE records(
    email TEXT REFERENCES users(email),
    lat DECIMAL,
    lon DECIMAL,
    depth TEXT,
    upload_date TIMESTAMP,
    comment TEXT,
    PRIMARY KEY (upload_date,email)
);

CREATE TABLE samples(
    date_taken TIMESTAMP,
    temp DECIMAL,
    intensity DECIMAL,
    upload_date TIMESTAMP,
    email TEXT,
    PRIMARY KEY(date_taken,upload_date,email),
    FOREIGN KEY (upload_date,email) REFERENCES records(upload_date,email)
);

samples被建模为一个弱实体,依赖于records. 如您所知,这意味着所有外键都继承自records并用于标识samples. 但是如果我们决定把它变成一个实体会发生什么?好吧,你可以用几种不同的方式来看待它,要么:

  1. 正如您所建议的,主键 fromrecords将不存在samples,我们将不得不分配某种任意的自动增量类型 ID。每条记录都包含数千个样本,用户将样本视为他们在现场记录的记录的一部分。他们希望按记录浏览样本,因此我们将有一个非常大的 samples表,没有明显的映射到他们在现实生活中所属的记录。

  2. 或者我们根本不将其建模为弱实体,而是认识到它需要能够用records一行来标识自己,所以我们分配一个upload_dateand email。如果我们将这两个条目设为外键,那么我们只是在没有意识到的情况下创建了一个弱实体。如果我们不这样做,那么我们的应用程序层必须负责检查以确保每个upload_dateemail也存在于 中records,而不是由数据库执行。

在这种情况下,创建samples一个弱实体(在其主键中包括外键)是最简单的选择(也是最有意义的)。

概括

当实体在现实生活中实际上很弱时,您应该将实体建模为弱。如果您有一个实体需要不同键的一部分来标识自己(具有作为其主键一部分的外键),那么它可能很弱。

你能改造系统以避免使用弱实体吗?可能,如果我们想要有未关联的样本,那么我们需要能够将它们设为空upload_dateemail这意味着它们不会在主键中,也不会是弱实体。我们将不得不做我在 1 中描述的事情。

于 2013-01-06T16:48:09.483 回答
0

主键必须是唯一的。永远。这里的所有都是它的。如果表中的数据不能自然地提供,您将创建一个代理键。

现在那些是什么。自然键由一个或多个现有列组成,而代理键是额外添加的列,通常是自动增量的。

自然键的一个很好的例子是countries表中的 ISO 国家代码。在此处添加自动增量列将一无所获。相反,您可以避免在某些查询中加入国家/地区表,因为您已经拥有 ISO 代码。

一个不好的,一个contacts表中的名称(或多个列)。这就是为什么在这种情况下最好使用代理键。

我就是这么想的,而且我很少(如果有的话)遇到任何有问题的布局问题。

一个实用的提示:你永远不会在UPDATE构成主键的列上运行。您将删除该行并使用新值重新插入它。这可以为您省去很多麻烦。

于 2013-01-06T17:13:54.880 回答