具有以下场景的复合主键或主代理键?

Composite primary key or primary surrogate key with following scenario?

我知道这个问题已经被问过很多次了,但我想解释一下我的情况,看看使用标识列作为主键而不是使用复合主键是否有任何好处。

我目前正在阅读两个文本文件:文件 1 包含汽车制造商和型号,而文件 2 包含汽车制造商、型号和年份。 File2 中的 Make、Model 组合将始终在 File1 中。

所以我创建了 table [Car],由 MakeId(标识)、MakeModel 列组成。 table [Car] 的数据如下所示。 [Car] 中的数据是 File1 的精确副本:

[MakeId]       [Make]      [Model]
1              HONDA       ACCORD
2              HONDA       CIVIC
3              FORD        FOCUS
4              FORD        ESCORT

对于 File2,我创建了 table [CarYear],其列为 CarYearId(身份)、MakeModelYear。 [CarYear] 中的数据是 File2 的精确副本:

[CarYearId] [Make]      [Model]     [Year]
1           HONDA       ACCORD      2002
2           HONDA       ACCORD      2001
3           HONDA       ACCORD      2004
4           HONDA       CIVIC       1998
5           FORD        FOCUS       1998
6           FORD        ESCORT      2001
7           FORD        ESCORT      2002

为什么我不应该使用 Make, Model 复合主键?鉴于我的情况,因为我在两个 table 中都有 Make & Model,所以我可以轻松地直接搜索第二个 table 而不必进行内部连接。

File1 has Make & Model of car . . .

所以感兴趣的数据看起来像这样。

make        model
--
HONDA       ACCORD
HONDA       CIVIC
FORD        FOCUS
FORD        ESCORT

列"make"显然不是候选键。据此数据样本可以看出,"model" 看起来 像一个候选键。事实上,几年前我不得不研究这个问题,我发现只有几个模型是由多个制造商制造的,其中 none 个是最新的。但这并不重要。

无论这里的候选key是{make,model}还是{model},这个table在6NF中。1如果我们假设唯一的候选key是 {make, model},我可能会在标准 SQL.

中这样实现它
create table car_models (
  make varchar(15) not null,
  model varchar(15) not null,
  primary key (make, model)
);

File2 has Make, Model, Year of car.

所以感兴趣的数据看起来像这样。

make        model       year
--
HONDA       ACCORD      2002
HONDA       ACCORD      2001
HONDA       ACCORD      2004
HONDA       CIVIC       1998
FORD        FOCUS       1998
FORD        ESCORT      2001
FORD        ESCORT      2002

按照前面table中对key的假设,这个table只有一个候选key,而且只有一个附加属性。它也属于 6NF。 SQL 版本可能如下所示。

create table car_model_years (
  make varchar(15) not null,
  model varchar(15) not null,
  model_year integer not null
    check (model_year between 1886 and 2099),
  primary key (make, model, model_year),
  foreign key (make, model) references car_models (make, model)
);

这些table有没有冗余数据。您不能在不破坏语义或损害数据完整性的情况下删除任何列。外键在 "car_model_years" 的行中重复,但这不是多余的——这 正是 外键是 for.

Is there any reason why I shouldn't use Make, Model a composite primary key?

作为理论(关系)问题,不,没有。如果您从 6NF 开始,添加代理 ID 编号 反规范化 即 table。 (6NF 需要一个 单一 候选密钥。)即使你 do 添加代理 ID 号码,你 still 必须将 {make, model} 声明为 not null unique。未能声明该约束会使 table 最终看起来像这样。

model_id  make   model
--
1         Honda  Accord
2         Honda  Accord
3         Honda  Accord

作为一个实际问题,而不是理论(关系)问题,这些 6NF tables 可能比使用代理 ID 号对它们进行非规范化表现得更好。例如,基于品牌和型号的 "car_model_years" 查询通常会使用仅索引扫描——它们根本不需要读取基础 table。

作为另一个实际问题,某些应用程序框架无法很好地处理除 ID 号之外的任何键。恕我直言,这证明使用更好的框架是合理的,但不会影响数据库的结构。


1. “...一个 'regular' 关系变量在 6NF 中当且仅当它由一个键组成,最多加上一个附加属性。” Date,CJ,深度数据库:从业者关系理论,第 147 页。常规关系变量是非时间关系变量。