Lookup Table -- 自然键还是代理键作为主键?

Lookup Table -- Natural or Surrogate key as primary key?

我有一个 table 用于记录许可证使用情况。每个许可证使用都需要与用户和主机相关联。 table 定义如下所示。

create table if not exists  per_user_fact
(
    per_user_fact_id        int unsigned        not null    auto_increment,
    time_of_day             char(16)            not null,
    license_served_id       smallint unsigned   not null,
    license_hours           numeric(10,2)       not null,
    role_name               varchar(64)         null,
    user                    varchar(128)        not null,
    host                    varchar(128)        not null,
    primary key (per_user_fact_id),
    foreign key (license_served_id) references served_license(served_license_id),
    foreign key (user, host) references user_host(username, hostname)
);

我想规范化此 table 以便将重复的 user/host 值移动到新的 table 中。

create table if not exists  user_host
(
    username                varchar(64)         not null,
    hostname                varchar(128)        not null,
    primary key (username, hostname)
);

对于 user_host table,我应该选择哪种主键 - 自然键还是代理键?我可以想到以下控制因素。

  1. 如果主键是自然的,即用户名和主机名的组合,则父 table per_user_fact 不需要额外的连接找出用户名和主机名。
  2. 如果主键是自然的,则会浪费存储空间,因为用户名和主机名值将在 table 中重复。
  3. 如果主键是代理项,则父项 table 需要额外的连接才能获取用户名和主机名的值。
  4. 如果主键是代理项,user_host table 上的索引会更快。

请指教

我非常喜欢使用代理主键,即使在这种情况下也是如此。当您连接到集群主键时,额外连接的成本可以忽略不计。

另外,假设usernamehostname(一起)长于四个左右的字符,代理键保存space。事实上,您可能会发现代理键会导致 更快的 查询,因为 per_user_fact 中的数据较小。较小的 table 占用较少的数据页,从而导致较少的 I/Os.

代理键的另一个优点是可以更改用户名和主机名而无需修改任何其他table。如果您使用数据字段进行联接,那么修改值需要更新多个 tables -- 一个更麻烦的操作。

我也喜欢代理 identity/serial/auto 增量键,因为它们还捕获 table 中的插入顺序。当然,还有其他方法(我的 table 通常有一个 CreatedAt 列,默认为插入时间)。但是,代理键也可以起到这个作用。

这些原因不构成对问题的 "right" 回答。有不使用代理人的正当理由。不过,对我来说,几乎所有 table 都有这样的主键。

鉴于问题中解释的情况,我会支持使用代理键。虽然自然的 PK 会给你在索引方面带来一些优势,但出于所有实际目的,使用代理会提供更多优势。

代理人让你的表格更苗条,给你审计的可能性等。

如果您正在使用 ORM(例如 Hibernate),则代理键更可取。否则,这是 a good article 阅读