更好地使用外键或分配唯一的ID?

时间:2018-10-09 01:15:20

标签: foreign-keys relational-database mariadb

数据库的简化模型是,假设我有一个A表,该表具有a, b, c, d列(因此(a, b, c, d)是主键)。然后,我还有另一个表B,用于为A中的每个条目存储一些类似于列表的数据,以保持第一个普通形式。

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

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

2 个答案:

答案 0 :(得分:3)

大多数基于SQL的数据库引擎确实要求将外键值至少两次物理存储(在引用表和父表中)。如果外键较大,可以选择不这样做。许多数据库设计人员会选择避免使用大的外键,部分原因是因为它们有额外的开销。

大多数DBMS提供了压缩数据的选项-是否使用外键。在许多情况下,这可能会补偿由于外键造成的物理数据重复。

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

答案 1 :(得分:1)

表存储:每个MySQL表都完全分开存储。在某些情况下,两个表可能位于同一个OS文件中,但是块(InnoDB为16KB)将完全分开。因此,(a,b,c,d)至少出现在数据集中的两个位置-一次出现在A中,一次出现在B中。

FOREIGN KEY 的副作用是创建一个额外的INDEX,因为那里还没有人。 (在您的情况下,您说它是PK,因此它已经是一个索引。)请注意,FK不需要UNIQUE索引。 (在您的情况下,PK是唯一的,但这似乎无关紧要。)

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

InnoDB中有一种形式的压缩:您可以将表声明为ROW_FOMAT=COMPRESSED。但这与重复数据删除(a,b,c,d)没有关系。

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

您何时应故意添加代理人id 作为PK?根据我的经验,只有大约三分之一的情况。 (其他人会争辩。)如果您没有任何辅助密钥,也没有FK引用它,则该替代方法会浪费空间和速度。如果只有一个辅助键或FK,则所需空间大约相同。到目前为止,您所描述的是最后一种情况。

表大小::如果您有一千行,则空间不太可能成为问题。一百万行可能会引发对空间的更认真思考。对于十亿行,“拉出所有停靠点”。

PK 技巧:不包括DATETIMETIMESTAMP,总有一天需要两行相同的时间。不要在PK中放入比隐式唯一性约束所需更多的列;如果这样做,则实际上会失去该约束。 (有例外。)