Jac*_*las 36 database-design primary-key surrogate-key
我了解代理/人工密钥的一个好处 - 它们不会改变,而且非常方便。无论它们是单场还是多场,都是如此——只要它们是“人造的”。
但是,有时将自动递增的整数字段作为每个表的主键似乎是一个策略问题。拥有这样一个单字段键是否总是最好的主意,为什么(或为什么不)?
需要明确的是,这个问题不是关于人工 vs 自然的——而是关于是否所有人工键都应该是单字段的
Joe*_*own 30
我会说不,并非总是如此,但大多数时候是的。.
在某些情况下,您不需要代理或人工密钥:
在某些情况下,老式的单调递增整数代理键并不理想。您可以拥有作为字母数字代理项的键。这些可能包括:
为什么大多数时候是的?这个问题最基本的答案是,如果您需要修改任何表上的主键值,那简直就是地狱。由于几乎用户可以看到或触摸的任何东西都可能会在某个时候进行更新,因此使用可见的键值会带来纯粹的地狱。使用代理键可以防止您落入这个陷阱。
话虽如此,请记住,YAGNI 在应用此概念时仍有空间。您不需要将带有 IDENTITY 键的代码表强制放入架构的每个角落和缝隙中,以防万一有人决定您的员工表中的男性性别符号需要从 M 更改为 X 或一些愚蠢的事情。
gbn*_*gbn 14
“这取决于”
是:当自然键很宽且非数字时,代理 IDENTITY/AUTONUMBER 字段很好。注意:这假设 SQL Server 和 Sybase 等中默认发生的“PK”和聚集索引的合并
否:当 2 个父键足够时,很多/很多表。或者当自然键较短且长度固定时,例如货币代码
当然,脑残的 ORM(阅读:(n)Hibernate)可能胜过这些规则......
编辑:再次阅读问题
具有 2 个代理父键的多/多表将具有多列 PK。
但是,它不需要另一个代理列。
如果表确实有代理(IDENTITY 等)键,则它不需要是多列。
您可以拥有一个包含代理的超级键,但这将强制执行其他规则(例如subtypes)
Jac*_*las 12
不。
我会说肯定存在单字段键不如复合键的情况,至少对于外键而言是这样。这并不是说如果您愿意,您也不应该有单字段代理键,但我个人更喜欢最常用作外键目标的键称为主键
我将尝试在以下示例中说明我的观点,其中:
brand 是汽车品牌,例如福特、丰田等dealer 是与品牌相关的实体经销商(例如仅销售福特汽车的福特经销商)model 是汽车类型,例如福特福克斯、福特嘉年华等stock 是每个经销商的当前前院汽车数量如果我们为dealer和创建一个单字段代理键,model如下所示:
create table brand( brand_id integer primary key );
create table dealer( dealer_id integer primary key,
brand_id integer references brand )
create table model( model_id integer primary key,
brand_id integer references brand )
create table stock( model_id integer references model,
dealer_id integer references dealer,
quantity integer,
primary key(model_id, dealer_id) )
Run Code Online (Sandbox Code Playgroud)
那么就可以插入一行stock,将福特dealer与“丰田”模型联系起来。添加brand_id references brand到stock只会使问题变得更糟。另一方面,如果我们将外键作为主键的一部分,如下所示:
create table brand( brand_id integer primary key );
create table dealer( brand_id integer references brand,
dealer_id integer,
primary key(brand_id, dealer_id) )
create table model( brand_id integer references brand,
model_id integer,
primary key(brand_id, model_id) )
create table stock( brand_id integer,
model_id integer,
dealer_id integer,
quantity integer,
primary key(brand_id, model_id, dealer_id),
foreign key(brand_id, model_id) references model,
foreign key(brand_id, dealer_id) references dealer )
Run Code Online (Sandbox Code Playgroud)
现在,“福特”经销商只能存货“福特”汽车的规则是由模型自然执行的。
请注意,在“复合键”示例中dealer_id,根据偏好可能是唯一的,也可能不是唯一的。它不需要是唯一的(即备用键),但是通过这样做(可能是一点存储空间)损失很少,并且它可以非常方便,所以这就是我通常设置它的方式,例如:
create table dealer( brand_id integer references brand,
dealer_id serial unique,
primary key(brand_id, dealer_id) )
Run Code Online (Sandbox Code Playgroud)