让我们这样看一下。你已经知道了一些。(PostgreSQL 语法;dbms 与规范化无关,仅用于实现。)
create table geo (
zip_code char(5) not null,
-- CHECK constraints on lat and long omitted.
latitude float not null,
longitude float not null,
primary key (zip_code),
unique (latitude, longitude)
);
create table users (
user_id integer not null,
username varchar(10) not null,
zip_code char(5) not null,
primary key (user_id),
foreign key (zip_code) references geo (zip_code)
on update cascade on delete restrict
);
很明显,这两个表都在 5NF 中。
您可以为地理表创建一个 ID 号,并且可以将 users.zip_code 替换为该 ID 号。但是用代理ID号替换真实数据与规范化无关,它不会改变这些表的正常形式。
用 id 号替换真实数据确实会改变性能;每次需要用户的邮政编码时,都需要加入才能获得。这不是一个完全可预测的变化。实际性能因 dbms、服务器、密钥宽度等而异。你不应该在测试你自己的表时遇到麻烦。您可能会发现,在多达几百万行的情况下,自然键的性能优于代理 ID 号。(这就是我在这里为我们的生产数据库测试设计时发现的。)
现在让我们稍微改变一下结构。
create table geo (
zip_code char(5) not null,
-- CHECK constraints on lat and long omitted.
latitude float not null,
longitude float not null,
primary key (zip_code),
unique (latitude, longitude),
-- Allows all three columns to be the target for a foreign key.
unique (zip_code, latitude, longitude)
);
create table users (
user_id integer not null,
username varchar(10) not null,
zip_code char(5) not null,
latitude float not null,
longitude float not null,
primary key (user_id),
-- This FK has to reference all three columns. If split, it's possible
-- to reference the latitude and longitude for the wrong zip code.
foreign key (zip_code, latitude, longitude)
references geo (zip_code, latitude, longitude)
on update cascade on delete restrict
);
尽管此更改确实引入了传递依赖,但在 user_id -> zip_code 和 zip_code -> latitude 等中,它不会导致任何插入、更新或删除异常。这是因为传递依赖关系中涉及的所有值都由对 5NF 表的单个外键引用覆盖。
表geo还在5NF;用户现在处于 2NF。我们在这里得到或失去了什么?
- 我们失去了磁盘空间来存储更广泛的外键数据和索引。
- 多达一定数量的行(可能是几百万),我们在 SELECT 查询上获得更快的性能。(我没有测试你的模式,因为我没有时间。但我已经通过使用自然键测量了 20 到 30 倍的速度增加。你的差异可能不会那么显着。)
- 我们在 INSERT 语句和大多数 UPDATE 语句上得到较慢的性能。(慢并不意味着慢。5msec 比 3msec 慢,但 5msec 不一定慢。我自己的大多数插入和更新都在几分之一毫秒内运行。)
所以构建一个测试模式,用几百万行填充它,然后测量性能。测试性能
- zip_code 上的外键,以及获取纬度和经度的连接,然后
- 使用 {zip_code, latitude, longitude} 上的外键重组和测试,然后
- 使用代理 ID 号和连接进行重组和测试以获取 zip_code、纬度和经度。
并在此处发布结果。我很想见到他们。