最好使用外键或分配唯一 ID?

Better to use foreign key or to assign unique ids?

数据库的简化模型是,假设我有一个 A 的 table,它有 a, b, c, d 列(因此 (a, b, c, d) 是主键).然后我有另一个 table B 来为 A 中的每个条目存储一些类似列表的数据,以便保持第一个范式。

因此,B table 将具有列 a, b, c, d, e,其中每个 e 条目是列表中的一个元素。在 B 中的 (a, b, c, d) 上有一个外键约束是很自然的,它强制执行完整性,即每个事物都必须首先存在于 A 中,然后是 B.

但是我想知道外键约束是否会让数据库引擎压缩或不复制B中的数据存储? (换句话说,(a, b, c, d) 是否会再次逐字存储并与 A 中的内容相同?)如果否,在这种情况下,是否为 A 中的每个条目分配一个唯一 ID 是更好的选择?

大多数基于 SQL 的数据库引擎确实要求外键值物理存储至少两次(在引用 table 和父 table 中)。在大外键的情况下可以选择不这样做会很好。许多数据库设计者会选择避免使用大外键,部分原因是他们有额外的开销。

大多数 DBMS 提供压缩数据的选项 - 外键或不。在许多情况下,这可能会弥补外键造成的物理数据重复。

然而,外键是一种逻辑结构,在数据库设计中,区分逻辑问题和物理问题很重要。

Table存储:每个MySQLtable完全独立存储。在某些情况下,两个 table 可能存在于同一个 OS 文件中,但块(InnoDB 为 16KB)将完全分开。因此,(a,b,c,d) 出现在数据集中至少两个地方——一次在 A 中,一次在 B 中。

A FOREIGN KEY 的副作用是创建一个额外的 INDEX 是不是已经存在了。 (在你的情况下,你说它是 PK,所以它已经是一个索引。)请注意,FK 不需要 UNIQUE 索引。 (在你的情况下,PK 是唯一的,但这似乎无关紧要。)

A secondary 索引(相对于PRIMARY KEY)对于table 存储在单独的 BTree,按键列排序。因此,如果 (a,b,c,d) 尚未被索引,FK 将导致 (a,b,c,d) 的额外副本,即在二级索引中。

InnoDB 中有一种压缩 的形式:您可以将table 声明为ROW_FOMAT=COMPRESSED。但这与去重(a,b,c,d)无关。

四列PK很多,不过还可以。如果它是 4 SMALLINT 个值,那么每个 PK 副本每行只有 8 个字节(加上开销)。如果它是一堆 VARCHARs,那么它可能会更大。

你什么时候应该故意添加代理人id作为PK?根据我的经验,只有大约三分之一的情况。 (其他人会争论。)如果您没有任何辅助键,也没有引用它的 FK,那么代理就是浪费 space 和速度。如果你只有一把副钥匙或FK,那么所需的space就差不多了。最后一种情况就是你目前所描述的。

Table 大小: 如果你有一千行,space 不太可能成为问题。一百万行可能会触发更认真地思考 space。对于十亿行,'pull out all stops'.

PK tips:不要包含DATETIMETIMESTAMP,哪天需要两行同一秒。不要在 PK 中放置多于隐式唯一性约束所需的列;如果你这样做,你实际上失去了这种约束。 (也有例外。)