Sql 引用非主键列的外键约束有哪些缺点?
我想知道使用主键列的引用关系与使用唯一键列的引用关系之间是否存在任何缺点(在SQL Server中,外键约束只能引用主键或唯一索引中的列) 在特定的数据库系统(如Microsoft SQL Server 2005)中,根据外键是否引用主键和唯一键,查询的解析方式是否存在差异 注意,我并不是在问使用不同数据类型的列来实现引用完整性、连接等之间的区别 纯粹作为一个示例,假设一个数据库中有一个“查找表”Sql 引用非主键列的外键约束有哪些缺点?,sql,sql-server,database,tsql,database-design,Sql,Sql Server,Database,Tsql,Database Design,我想知道使用主键列的引用关系与使用唯一键列的引用关系之间是否存在任何缺点(在SQL Server中,外键约束只能引用主键或唯一索引中的列) 在特定的数据库系统(如Microsoft SQL Server 2005)中,根据外键是否引用主键和唯一键,查询的解析方式是否存在差异 注意,我并不是在问使用不同数据类型的列来实现引用完整性、连接等之间的区别 纯粹作为一个示例,假设一个数据库中有一个“查找表”dbo.Offices: CREATE TABLE dbo.Offices ( ID i
dbo.Offices
:
CREATE TABLE dbo.Offices (
ID int NOT NULL IDENTITY(1,1) CONSTRAINT PK_Codes PRIMARY KEY,
Code varchar(50) NOT NULL CONSTRAINT UQ_Codes_Code UNIQUE
);
还有一个表dbo。患者:
CREATE TABLE dbo.Patients (
ID int NOT NULL IDENTITY(1,1) CONSTRAINT PK_Patients PRIMARY KEY,
OfficeCode varchar(50) NOT NULL,
...
CONSTRAINT FK_Patients_Offices FOREIGN KEY ( OfficeCode )
REFERENCES dbo.Offices ( Code )
);
与以下替代版本相比,上述T-SQL代码中的表dbo.Patients
及其约束FK_Patients_Offices
有哪些缺点:
CREATE TABLE dbo.Patients (
ID int NOT NULL IDENTITY(1,1) CONSTRAINT PK_Patients PRIMARY KEY,
OfficeID int NOT NULL,
...
CONSTRAINT FK_Patients_Offices FOREIGN KEY ( OfficeID )
REFERENCES dbo.Offices ( ID )
);
显然,对于第二版本的dbo.Patients
,如果对dbo.Offices
的code
列中的值进行更改,则不需要更新OfficeID
列中的值
同样(显而易见)的是,将dbo.Offices
的code
列用于外键引用在很大程度上违背了代理键列ID
的目的——这纯粹是示例的产物。[对于外键引用可能合理使用非主键的表,有没有更好的例子?]我能想到的最重要的一个例子是,如果他们对办公室重新编号,您要么会失去完整性,要么需要更新这两个表。不管可能性有多大
除非您有不合理的大办公室代码,否则性能影响是非常小的,甚至比您可能预期的还要小
对于大多数人来说,它不被认为是数据库设计的重要决定因素。假设您在代码列上添加了一个索引(一旦您引用它,您肯定应该立即添加索引),有什么可以反对去掉整个ID列,同时使用代码列作为PK吗?为什么你认为会有任何缺点
恰恰相反!很高兴看到您像每个人一样强制执行引用完整性!没有缺点-只是做这件事的良好实践
我看不出引用唯一索引与引用主键有任何功能上的差异或任何问题
更新:由于您对性能或数据类型相关的问题不感兴趣,最后一段可能不会增加任何附加值
我看到的唯一一件小事是,您的OfficeCode
既是VARCHAR
,因此您可能会遇到排序规则和/或大小写问题(大写/小写,取决于您的排序规则),并且JOIN的大小相当大(最多50字节)而可变长度字段可能不如基于小的固定长度INT
列的连接条件有效。没有缺点
然而
为什么在Office表中有ID列?当在其他表中作为外键使用时,代理键用于减少空间并提高性能,例如varchar列
如果要将varchar列用于外键,则不需要代理键
使用FKs的“代码”列浪费了具有标识的大部分好处。主键是候选键,与任何其他候选键没有根本区别。普遍遵守的惯例是,每个表中有一个候选键被指定为“主”键,并且这是用于所有外键引用的键
以这种方式选择一个键的一个可能优势是,您可以让数据库用户更清楚地使用该键:他们不必查看每个引用表,就可以知道哪个键是被引用的键。但是,这完全是可选的。如果您觉得这样做很方便,或者要求外键引用其他键,那么我建议您这样做。大缺陷
我们能够在dbo.Patients.OfficeID中输入一些在dbo.Offices.ID中没有的值
说有参考文献是没有意义的。????如果办公室的ID
发生变化,则OfficeCode
上的引用仍然完全有效。。。。。或者你是什么意思?当有人更改OfficeCode
时?你可以在FK关系中添加一个ON UPDATE CASCADE
子句来管理这一点……例如,如果你的办公室号码(“w-823”,ID=562)从“w-B23”更改为“w-B23a”,因为他们将其拆分为两个(w-823a和w-823b),那么办公室表格可以更改,而无需更改你的病历。好,好的一点-正如我所提到的,在较小的ID(如INT)上进行连接也很可能会提高性能。无论外键使用主键还是唯一键,对引用列的更改都会破坏引用完整性或需要更新。@Kenny Evitt,但作为代理键的PK与基于字符串的字段相比变化的可能性要小得多。这就是为什么如果您有一个代理键来强制引用完整性,那么使用代理键通常会更好。出于我刚才提到的原因(大键、变长键),仅使用OfficeCode
作为主键(因此默认情况下自动使用集群键)将是一个非常糟糕的主意!不要那样做!!一个好的集群密钥应该是使用-狭窄的、唯一的、静态的和不断增加的。看看那个主题,谢谢你的洞察力。在我看来,“代码为FK”方法的一个主要缺点是可能会损害可维护性,因为新开发人员编写视图、连接。。。他们可能会认为