这就是我的意思。假设我有一个名为 Names
的表,它只是一个唯一的名称列表,
Names
================
name
================
"Charlie"
----------------
"George"
----------------
"Bernie"
----------------
以及引用这些名称的另一个表,
OtherTable
=========================
... | name | ....
=========================
... | "Charlie" | ....
-------------------------
... | "Charlie" | ....
-------------------------
... | "Charlie" | ....
-------------------------
数据库引擎是否在OtherTable
中存储实际名称?还是通过存储对它们的隐藏引用来优化?
如果没有,这意味着我应该添加一个列来Names
id | Names
==================
1 | name
==================
2 | "Charlie"
------------------
3 | "George"
------------------
4 | "Bernie"
------------------
并像引用它一样
OtherTable
=========================
... | name_id | ....
=========================
... | 1 | ....
-------------------------
... | 1 | ....
-------------------------
... | 1 | ....
-------------------------
但是,Names
表上的附加列不需要作为主键,因为names
是唯一的,可以像主键一样服务器(除了按name
查找的效率可能略低,因为字符串比较比整数比较慢(。
这不是第22条军规的情况吗?
功能和逻辑方面应该优先于(非常(次要的效率方面。
在有意义的列(如name
列(上链接的一个问题是,有意义的列往往会发生变化。 例如,您可能会发现名称中的拼写错误并想要更改它。另一方面,作为PK的身份列是没有意义的,因为它除了是内部使用的标识符之外没有其他含义,通常不会向用户显示。由于没有人关心它的真正价值,所以没有人会想要改变它。
也可以不区分大小写,可以具有不同的长度,不同的排序规则,不同的编码和不同的类型(varchar,nvarchar,char,nchar(。int
很简单(int
是int
是int
(。
如果您将 names 表用作与其他表无关的简单查找表,即,如果您只想将其用作填充文本框的便捷方式,但不需要任何引用完整性(无外键(,那么您可以将其用作主键。
顺便说一句:数据库不会创建任何神奇的、隐藏的引用,而是完全按照你告诉它做的事情去做。
数据库将在表中存储实际数据值。 如果查找表的主键是字符串,则该字符串可能会在 OtherTable
中存储多次。
根据数据的性质,对Names
表使用合成整数主键可能会更节省空间。 但是,您可能会为此付出代价,因为要做额外的工作来连接两个表,而不仅仅是从OtherTable
获得name
。 另一方面,当"查理"决定现在要被称为"查尔斯"时,合成密钥使更新name
值变得更加容易。 与任何架构决策一样,您必须确定权衡是否值得。
在"其他"表中,引擎将存储您在创建列时告诉它的内容(这将是一个字符串(。所以是的,那里有冗余。
在此特定方案中,您正在通过将字符串替换为对相同数据的较短引用来执行某种形式的数据压缩。许多通用压缩算法都做类似的事情。
如果您关心空间节省,这是一件有效的事情。这是一个复杂的权衡,有很多优点和缺点。
我认为你没有错过任何主要方面。