数据库的简化模型是,假设我有一个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是一个更好的选择吗?
答案 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 技巧:不包括DATETIME
或TIMESTAMP
,总有一天需要两行相同的时间。不要在PK中放入比隐式唯一性约束所需更多的列;如果这样做,则实际上会失去该约束。 (有例外。)