关于外键数据如何存储在SQL中的问题

时间:2011-08-24 21:41:06

标签: mysql sql foreign-keys

我知道这是超基本的,但这是我一直持有的假设,并且想验证它是否属实(通常,具体针对各种实现的细节)

假设我有一个包含文本列“Fruit”的表。在该专栏中,只出现了四个值中的一个:梨,苹果,香蕉和草莓。我有一百万行。

如果我将其提取到另一个具有Fruit列且只有那四行的表中,然后将原始列作为外键,而不是重复(平均)每个25万次数据,那么它是否会保存空间?

我假设四个水果名称只存储一次,而且百万行现在有指针或索引或某种引用到第二个表中。

如果我的行值比短水果名称长,我认为节省/优化甚至更大。

7 个答案:

答案 0 :(得分:6)

外键关系两侧字段的数据类型必须相同。

如果父表的键字段是(例如)varchar(20),则从属表中的外键字段也必须是varchar(20)。这意味着,是的,你必须在每张桌子上重复X万行'Apple'和'Pear'和'Banana',其外键指向水果桌。

通常使用数字字段作为键(int,bigint)更有效,因为那些可以用很少的CPU指令进行比较(通常可以直接进行一次cpu指令比较)。另一方面,字符串需要循环和相对昂贵的设置。所以,是的,最好将水果名称存储在某个表格中,并使用相关的数字ID字段作为外键。

当然,您应该对这两种设置进行基准测试。这些只是一般的拇指规则,您的特定要求/设置实际上可以更快地使用字符串作为键版本。

答案 1 :(得分:5)

这是正确的。

你应该

table fruits
id   name
1    Pear
2    Apple
3    Banana
4    Strawberry

ID是主键。 在第二个表中,您将只使用此表的id。这将节省您的物理空间,并使您的选择语句更快地运行。
此外,这种结构可以让您轻松添加新水果。

答案 2 :(得分:2)

  

而不是重复数据(平均)25万次   每一个,如果我将它提取到另一个具有Fruit列的表中   只是这四行,然后使原始列成为外键,   它节省空间吗?

如果“Fruit”是“查找”表的PRIMARY KEY,则为“否”,因此它也必须是“大”表中的FOREIGN KEY。

但是,如果您在“查找”表中创建一个小的代理PRIMARY KEY(例如整数“id”),而不是在“大”表中使用它作为FOREIGN KEY,那么您将节省空间。

答案 3 :(得分:2)

首先是的,它会节省空间,因为int - 4个字节,TINYINT - 1个字节。其次,使用TYPE INT搜索此字段将比VARCHAR更快。除此之外,如果您的数据将来没有变化,您可以使用ENUM。使用枚举,您将获得与辅助表相同的更快结果,您将避免额外的连接。

答案 4 :(得分:2)

规范化不仅仅是关于空间,它通常是冗余和建模数据行为,也是关于仅更新一行以进行更改 - 并通过仅更新最少量的数据来减少锁的范围。

答案 5 :(得分:1)

可悲的是,你假设错了:为每个引用表重复地物理存储这些值。有些SQL产品确实只存储了一次这个值,但大部分都没有,特别是那些基于磁盘上连续存储的更受欢迎的产品。

这就是最终用户认为需要以伪装使用整数'代理键'来实现自己的点的原因。系统替代品将是优选的,例如对于用户来说是不可见的,就像系统维护索引的“值”并且不能由用户直接操作一样。滚动自己的问题是它们成为逻辑模型的一部分。

答案 6 :(得分:0)

我知道你确实想要使用外键。 Aaah,Marc B刚刚公布了对FKs的影响。 但是使用第二个表作为外部“名称提供者”肯定会节省空间。你需要一个关于fruit.fruit_id的额外索引。这个将是相当小,它将是NUMERIC。比char或varchar上的索引更快。