2

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

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)
);

我想规范化这个表,以便将重复的用户/主机值移动到这样的新表中。

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

对于user_host表,我应该选择什么样的主键 - 自然或代理?我可以想到以下控制因素。

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

请指教。

4

3 回答 3

6

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

此外,假设usernameand hostname(一起)长于四个左右的字符,代理键可以节省空间。事实上,您可能会发现代理键会导致查询速度更快,因为其中的数据per_user_fact更小。较小的表占用较少的数据页,从而导致较少的 I/O。

代理键的另一个优点是可以在修改任何其他表的情况下更改用户名和主机名。如果您使用数据字段进行连接,那么修改值需要更新多个表——这是一个更繁琐的操作。

我也喜欢代理身份/序列/自动增量键,因为它们还捕获表中的插入顺序。当然,还有其他方法(我的表通常有一CreatedAt列默认为插入时间)。但是,代理键也可以扮演这个角色。

这些理由并不构成对该问题的“正确”答案。不使用代理是有正当理由的。不过,对我来说,几乎我所有的表都有这样的主键。

于 2015-12-19T15:41:32.753 回答
0

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

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

于 2018-08-19T18:57:52.483 回答
0

如果您使用的是 ORM(例如 Hibernate),则最好使用代理键。否则,这是一篇好文章

于 2022-02-24T00:06:35.653 回答