为什么要使用多列作为主键(复合主键)


109

此示例摘自w3schools

CREATE TABLE Persons
(
    P_Id int NOT NULL,
    LastName varchar(255) NOT NULL,
    FirstName varchar(255),
    Address varchar(255),
    City varchar(255),
    CONSTRAINT pk_PersonID PRIMARY KEY (P_Id,LastName)
)

我的理解是,两列(P_IdLastName)一起代表该表的主键Persons。这样对吗?

  • 为什么有人要使用多列而不是单列作为主键?
  • 给定表中可以将多少列一起用作主键?


1
@马丁·彼得斯(Martijn Peters)。为什么答案被删除?
PerformanceDBA

Answers:


119

您的理解是正确的。

在许多情况下,您会这样做。一个例子是在诸如OrderHeader和的关系中OrderDetail。中的PK OrderHeader可能是OrderNumber。中的PK OrderDetail可能是OrderNumberAND LineNumber。如果是这两者之一,则不是唯一的,但是可以保证两者的组合是唯一的。

替代方法是使用生成的(非智能)主键,例如在这种情况下OrderDetailId。但是,您将不会总是很容易地看到这种关系。有些人喜欢一种方式。有些人更喜欢另一种方式。


2
如果我使用branch_id并在两个数据库之间使用复制,这将解决id的重复吗?
Mhmd 2014年

11
请注意,在许多情况下,使用生成的主键时,您通常仍希望在复合值上使用唯一键。
培根钻头

请详细说明“有些人更喜欢一种方式;有些人更喜欢另一种方式”。
用户名

1
请问详细吗?不知道该说些什么。我知道有些人喜欢将多个串联的字段作为键,因为直观上更容易理解他们在看什么。我知道其他人更喜欢只为每行分配一个唯一键,因为它更容易键入。那是你的要求吗?
MJB

该消息是给@Username的。我忘了导演。
MJB

26

复合主键的另一个示例是关联表的用法。假设您有一个包含一组人员的人员表和一个包含一组组的组表。现在,您要在个人和组上创建多对多关系。意味着每个人都可以属于多个组。这是使用复合主键的表结构。

Create Table Person(
PersonID int Not Null,
FirstName varchar(50),
LastName varchar(50),
Constraint PK_Person PRIMARY KEY (PersonID))

Create Table Group (
GroupId int Not Null,
GroupName varchar(50),
Constraint PK_Group PRIMARY KEY (GroupId))

Create Table GroupMember (
GroupId int Not Null,
PersonId int Not Null,
CONSTRAINT FK_GroupMember_Group FOREIGN KEY (GroupId) References Group(GroupId),
CONSTRAINT FK_GroupMember_Person FOREIGN KEY (PersonId) References Person(PersonId),
CONSTRAINT PK_GroupMember PRIMARY KEY (GroupId, PersonID))

很好的解释:我认为对m-n关系(归一化的方式)的属性需求是关键。
狼”

也许添加一点好处的解释可能会更好
Martian2049 '18年

10

W3Schools示例并未说明何时应使用复合主键,仅提供了与其他键使用相同示例表的示例语法。

他们选择的示例可能通过组合无意义的键(P_Id)和自然键(LastName)来误导您。主键的这种奇怪选择表明,根据模式,以下行是有效的,并且对于唯一地识别学生是必需的。直觉上这是没有意义的。

1234     Jobs
1234     Gates

进一步阅读:伟大的主键辩论,或者只是谷歌meaningless primary keys,甚至细读 SO问题

FWIW-我的2美分是避免使用多列主键,并使用单个生成的id字段(代理键)作为主键,并在必要时添加其他(唯一)约束。


1
1)“重大主键辩论”链接特别愚蠢,该信息是自我服务且虚假的。2)无法避免使行唯一的列上的索引。具有索引的“代理” ID始终是附加列和附加索引。有点傻,因为它是多余的。而且慢一点。
PerformanceDBA

2
“重大的主键辩论”并不愚蠢。对于不是sql开发人员或sql DBA的开发人员来说,这是一个非常有效的问题,他们不会将所有时间都花在sql上。即使在纯sql中,我也希望在加入时将无意义的自动生成的键作为主键,而不是必须记住将n位数据传递为自然键。欢迎您提出您的观点,但我们希望您不要这么不屑一顾。
罗伯特·保尔森

4

每当您要确保多个属性组合的唯一性时,就可以使用复合键(具有多个属性的键)。单个属性键将无法实现同一目的。


1
至于确保唯一键,您可能依赖于两个属性的组合来形成一个在逻辑上无法重复的键,例如,来自较大数据集的人和毕业日期就是一个例子。
约翰·马克

3

是的,它们都是主键。特别是在没有代理键的表中,可能有必要将多个属性指定为每条记录的唯一标识符(不好的例子:名字和姓氏都相同的表可能要求将它们的组合独特)。


3

通常,键中的多列比代理键的性能要差。我更喜欢使用代理键,然后在多列键上具有唯一索引。这样,您可以拥有更好的性能,并保持所需的唯一性。甚至更好的是,当该键中的值之一更改时,您也不必更新215个子表中的一百万个子项。


1
1)性能。不在SQL平台中(可能假装为“ sql”和免费软件)。2)偏好无关紧要。这些表对于完整性的要求是相关的。3)具有索引的“代理” ID始终是附加列和附加索引。因此,在任何平台上,运行速度都会变慢。再表演,你就矛盾了。4)如果你不知道如何更新传说中的“万个儿童条目215代表” 正常,问一个问题。
PerformanceDBA

2
我不同意“键中的多个列通常比替代键的性能要差”的说法。在考虑关系时,通常通常需要额外查询才能获得关系的代理键。在这一点上,这是一个完整的额外往返行程,会降低性能。
ttugates

3

你的第二个问题

给定表中可以将多少列一起用作主键?

是特定于实现的:它是在实际使用的DBMS中定义的。[1],[2],[3]您必须检查所用数据库系统的技术规范。有些非常详细,有些则没有。在网络上搜索此类限制可能很困难,因为术语会有所不同。复合主键一词应为必填;)

如果找不到明确的信息,请尝试创建测试数据库,以确保可以稳定(特定地)处理超出限额的情况(这是可以预期的)。请谨慎获取有关此内容的正确信息:有时会累积限制,并且在不同的数据库布局下您会看到不同的结果。



2

在关系数据库中使用中间表时,在多个表上使用主键非常方便。

我将使用我曾经创建的数据库作为示例,尤其是该表中的三个表。几年前,我为一个网络漫画创建了一个数据库。一个表称为“漫画”-列出所有漫画,标题,图像文件名等。主键为“漫画”。

第二个表是“字符”-它们的名称和简要说明。主键位于“字符名”上。

由于每个漫画(有一些例外)都有多个字符,并且每个字符都出现在多个漫画中,因此在“字符”或“漫画”中添加一栏来反映这一点是不切实际的。相反,我创造了一个第三张桌子,称为“漫画字符”,该列表列出了哪些字符出现在哪些漫画中。由于此表本质上连接了两个表,因此只需要两列:charname和comicnum,并且主键都在这两个表上。


1

我们创建复合主键以保证组成单个记录的唯一性列值。这是一个约束,有助于防止插入不应重复的数据。

即:如果所有学生ID和出生证明号都唯一地分配给一个人。然后,使一个人的主键由学生证和出生证号码组成是一个好主意,因为它可以防止您意外地插入两个具有不同学生证和相同出生证的人。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.