Sql 为什么我读到这么多关于使用复合键的负面意见?
我正在开发一个Access数据库,它喜欢自动编号的标识符。每个表都使用它们,只有一个表使用由一个人的名字、姓氏和生日组成的键。不管怎么说,人们开始在使用重复项时遇到很多问题,因为表示关系的表可能会持有相同的关系两次或更多次。我决定通过为关系表实现复合键来解决这个问题,从那以后我就再也没有遇到过重复键的问题Sql 为什么我读到这么多关于使用复合键的负面意见?,sql,ms-access,primary-key,composite-key,composite-primary-key,Sql,Ms Access,Primary Key,Composite Key,Composite Primary Key,我正在开发一个Access数据库,它喜欢自动编号的标识符。每个表都使用它们,只有一个表使用由一个人的名字、姓氏和生日组成的键。不管怎么说,人们开始在使用重复项时遇到很多问题,因为表示关系的表可能会持有相同的关系两次或更多次。我决定通过为关系表实现复合键来解决这个问题,从那以后我就再也没有遇到过重复键的问题 所以我想知道复合密钥在访问世界中的坏名声是怎么回事?我想写一个查询要稍微困难一些,但至少你不必每次在前端输入甚至编辑数据时都进行大量的检查。他们是超级低效还是什么 它使查询和维护变得复杂。如果
所以我想知道复合密钥在访问世界中的坏名声是怎么回事?我想写一个查询要稍微困难一些,但至少你不必每次在前端输入甚至编辑数据时都进行大量的检查。他们是超级低效还是什么 它使查询和维护变得复杂。如果你真的对这个主题感兴趣的话,我建议你看看已经涵盖这个主题的帖子的数量。这将为您提供比这里的任何一个响应更好的信息
如果您只使用纯自编的
SQL
来访问您的数据,那么它们就可以了
但是,一些ORM
s、适配器等需要一个PK
字段来标识记录
还请注意,复合主键几乎总是自然键(创建代理复合键几乎没有意义,您也可以使用单个字段)
复合主键最常见的用法是多对多链接表
使用自然键时,应确保它们是固有唯一的和不可变的,即一个实体在模型反映后始终由键的相同值标识,并且任何值只能标识一个实体
你的情况并非如此
首先,一个人可以改变自己的名字甚至生日
其次,我很容易想象两个约翰·史密斯在同一天出生
前者意味着,如果一个人更改了姓名,您必须在每个涉及人的表中更新姓名;后者意味着第二个John Smith
将无法进入您的数据库
对于像你这样的情况,我会考虑在模型中添加一个代理标识符。
复合键对于单个表来说是很好的,但是当你开始创建表之间的关系时,它会有点大。
考虑两个表Person
和Event
,它们之间的多对多关系称为约会
如果在Person
表中有一个由名字、姓氏和出生日期组成的复合键,在Event
表中有一个由地点和姓名组成的复合键,则在约会
表中会有五个字段来标识关系
约束关系的条件将非常长:
select Person,*, Event.*
from Person, Event, Appointment
where
Person.FirstName = Appointment.PersonFirstName and
Person.LastName = Appointment.PersonLastName and
Person.BirthDate = Appointment.PersonBirthDate and
Event.Place = Appointment.EventPlace and
Event.Name = Appointment.EventName`.
另一方面,如果您为人员
和事件
表设置了自动编号键,则在约会
表中只需两个字段即可识别关系,条件要小得多:
select Person,*, Event.*
from Person, Event, Appointment
where
Person.Id = Appointment.PersonId and Event.Id = Appointment.EventId
如果您的RDBMS支持它们,并且您正确(一致)使用它们,那么复合PK上的唯一键应该足以避免重复。至少在SQL Server中,您还可以针对唯一密钥而不是PK创建FK,这非常有用
单个“id”列(或代理键)的优点是,它可以通过使用更窄的键来提高性能。因为该键可以携带到该表上的索引(作为从索引行返回物理行的指针),而其他表可以作为FK列携带,这样可以减少空间并提高性能。不过,这在很大程度上取决于RDBMS的特定体系结构。不幸的是,我对访问权限不够熟悉,无法对此发表评论
正如Quassnoi所指出的,一些ORM(以及其他第三方应用程序、ETL解决方案等)没有处理复合密钥的能力。不过,除了一些ORMs之外,最新的第三方应用程序都支持复合密钥。不过,一般来说,ORMs在采用这一点上有点慢
我个人对复合键的偏好是,尽管一个独特的索引可以解决重复的问题,但我还没有看到一个开发商店真正充分使用它们。大多数开发人员对此很懒惰。他们抛出一个自动递增的ID,然后继续前进。然后,六个月后,他们付给我很多钱来修复他们的重复数据问题
另一个问题是,自动递增的ID通常不可移植。当然,您可以在系统之间移动它们,但由于它们在现实世界中没有实际的基础,因此在给定实体的所有其他信息的情况下,不可能确定一个实体。这在ETL中成为一件大事
PKs在数据建模领域是一件非常重要的事情,它们通常值得更多的思考,如果您希望数据保持一致和干净,请“添加一个自动递增的ID”
代理键也很有用,但我更喜欢在遇到已知的性能问题时使用它们。否则,这就是浪费时间试图解决一个你可能根本没有的问题的典型问题
最后一个提示。。。在交叉引用表(或一些人称之为连接表)上,除非ORM需要,否则添加代理键(在我看来)有点愚蠢。复合键不仅是复合主键,也是复合外键。我这是什么意思?我的意思是,每个引用原始表的表在复合键中的每一列都需要一列
下面是一个简单的例子,使用一般的学生/班级安排
人
名字
姓氏
地址
类别
类名
UNIQUE (employee_number, start_date); -- simple constraint
UNIQUE (employee_number, end_date); -- simple constraint
UNIQUE (employee_number, start_date, end_date); -- simple constraint
CHECK (
NOT EXISTS (
SELECT Calendar.day_date
FROM Calendar, Payroll AS P1
WHERE P1.start_date <= Calendar.day_date
AND Calendar.day_date < P1.end_date
GROUP
BY P1.employee_number, Calendar.day_date
)
); -- sequenced key i.e. no over-lapping periods for the same employee