我有几个数据库表,只包含了一列和很少的行,通常只是另一个系统中定义的某个ID。这些表然后被其他表使用外键引用。例如,一个表包含国家代码(SE,DK,US等)。所有值始终是唯一的自然键,并且它们在其他(遗留)系统中被用作主键。
似乎没有必要为这些表引入新的代理键,对吗?
一般来说,在什么情况下不应使用代理键?
我有几个数据库表,只包含了一列和很少的行,通常只是另一个系统中定义的某个ID。这些表然后被其他表使用外键引用。例如,一个表包含国家代码(SE,DK,US等)。所有值始终是唯一的自然键,并且它们在其他(遗留)系统中被用作主键。
似乎没有必要为这些表引入新的代理键,对吗?
一般来说,在什么情况下不应使用代理键?
你的自然键必须是绝对、肯定、不允许例外的唯一的(像姓名、社会安全号码等通常看起来是唯一的,但实际上并不是)
你的自然键应该尽可能小,例如不超过4个字节的INT类型大小(不要在主键中使用VARCHAR(50),特别是在SQL Server中不要在聚集键中使用VARCHAR(50)!)
你的自然键应该是稳定的,即永远不会改变(好吧,对于ISO国家代码来说,这几乎是一个假设——除非像南斯拉夫或苏联这样的国家崩溃,或者像两个德国那样合并——但这种情况很少见)
如果满足这些条件,你可以考虑将自然键作为主键——但这应该是所有表中的2%的例外情况,而不是常规情况。
如果自然键能够被真正信任,那么将其用于标识目的是一个好主意。请参阅Marc_S的回答,了解一些自然键不能被信任的情况。不要过于担心效率问题。即使像VIN(车辆识别号码)这样长的东西也不会拖慢你的数据库。如果你认为会有影响,可以进行一些测试,注意效率并非线性扩展。
声明主键的主要原因是防止表滑出第一范式,从而不再表示关系。使用自动递增的代理键可能会导致两个具有不同id字段但否则相同的行。这将带来一些不符合第一范式数据的问题。而且用户无法提供帮助,因为他们看不到id字段。
如果一张表的行可以通过两个或多个外键的组合来确定,那么你拥有一个关系表,有时称为链接表或联接表。通常最好声明由所有所需外键组成的复合主键。
如果上述选择导致性能缓慢,有时可以通过创建一些额外的索引来解决问题。这取决于你对数据的操作方式。