复合主键为什么还在?

Tes*_*son 58 mysql sql-server database-design

我被分配将数据库迁移到中产阶级ERP.新系统在这里和那里使用复合主键,从实用的角度来看,为什么?

与自动生成的ID相比,我只能看到消极方面;

  • 外键变得模糊
  • 更难迁移或db-redesigns
  • 商业变革不灵活.(我的车没有注册表...)
  • 通过约束更好地实现相同的完整

它正在回归到候选键的设计概念,我没有看到它的意义.

它是软盘日的习惯/神器(最小化空间/索引),还是我错过了什么?

//编辑//刚发现好的SO帖子:复合主键与唯一对象ID字段 //

Qua*_*noi 57

当主键是非代理的时,复合键是必需的,并且固有的,嗯,复合键,即可分解为几个不相关的部分.

一些现实世界的例子:

  • 多对多链接表,其中主键由相关实体的键组成.

  • 多租户应用程序何时tenant_id是每个实体的主键的一部分,并且实体仅可在同一租户内链接(受外键约束).

  • 处理第三方数据的应用程序(已提供主键)

请注意,逻辑上,所有这些都可以使用UNIQUE约束(除了代理PRIMARY KEY)来实现.

但是,有一些实现特定的东西:

  • 有些系统不允许FOREIGN KEY引用任何不是a的东西PRIMARY KEY.

  • 有些系统只会在a上对表进行聚类PRIMARY KEY,因此使得组合PRIMARY KEY可以提高连接到组合上的查询的性能.


Ali*_*tad 40

复合主键在将其用作其他表中的外键时会提供更好的性能,并减少表读取 - 有时它们可​​以节省生命.如果使用代理键,则必须转到该表以获取自然密钥信息.

例如(纯粹的例子 - 所以我们不在这里谈论数据库设计),让我们说你有一个ORDER表和ORDER_ITEM.如果您使用ProductIdLineNumber(更新:并且正如Pedro提到的OrderId甚至更好OrderNumber)作为复合主键ORDER_ITEM,那么在您的交叉表中SHIPPING,您将能够拥有ProductId SHIPPING_ORDERITEM.这可以大大提高您的性能,例如,如果您已经用完该产品,并且需要找出ProductId需要在不需要加入的情况下发货的所有产品.

另一方面,如果使用代理键,则必须加入并最终得到效率非常低的SQL执行计划,它必须在多个索引上进行书签查找.

查看有关使用代理键成为主要问题的书签查找的更多信息.

  • +1,恰好是复合主键的重点. (2认同)

HLG*_*GEM 40

我个人更喜欢使用代理键.但是,在连接仅包含来自其他两个表的ID的表(以创建多对多关系)时,复合键是可行的方式,因此将它们取出会使事情变得更加困难.

有一种观念认为代理键总是很糟糕,如果你没有通过使用自然键进行记录的独特性,那么你的设计就会很糟糕.我强烈不同意这一点(如果你没有存储SSN或其他一些独特的价值,我会藐视你为个人桌子提供一个自然键.)但是很多人觉得有必要进行适当的规范化.

有时使用复合键可以减少加入另一个表的需要.有时却没有.因此,有时复合键可以提高性能以及可能会损害性能的时间.如果密钥相对稳定,那么在选择查询时性能会更快.但是,如果它可能会像公司名称那样发生变化,那么当公司A更改其名称并且您必须更新一百万条相关记录时,您可能会受到伤害.

在数据库设计中没有一种尺寸适合所有.有时间复合键是有用的,有时它们是可怕的.有时代理键是有用的,有些时候不是.

  • **非常重要的说明:**社会安全号码不是唯一的,因此不是一个好的候选人.http://blogs.computerworld.com/node/5969 (17认同)
  • 了解.我会更清楚一点:即使你的表中没有重复的SSN,**它仍然不能被视为候选**,否则你将来可能会受到惩罚(如文章中所述). (7认同)
  • @BoffinbraiN:候选键不能好或坏,它可以存在与否.如果表中有两个或多个相同的`SSN`,那么`SSN`不是候选键,如果不是,那么它就是. (3认同)
  • @BoffinbraiN:某个东西是否是候选键不是在同一个表中存在两个相同的值(或元组)(这意味着在数据已经存在之后你正在进行数据库设计!),而是是否或者不是可能的数据集(为了讨论,我们会说它是所有人)可能会产生重复的值.在这方面,由于SSN不能保证在所有可能的人中都是唯一的,因此SSN不是候选密钥. (2认同)
  • 同意,+1为平衡的答案.反模式不使用代理键,也不使用复合键.反模式是在每种情况下盲目地使用一种解决方案或另一种解决方案. (2认同)

A-K*_*A-K 9

自然主键很脆弱.

假设我们在自然PK(CountryCode,PhoneNumber)周围构建了一个系统,并且在未来几年我们需要添加Extension,或者将PK更改为一列:Email.如果将这些PK列传播到所有子表,则会变得非常昂贵.

几年前,有些系统是在假设社会安全号码是自然PK的情况下构建的,并且当SSN变得非独特且可以为空时,必须重新设计以使用身份.

因为我们无法预测未来,我们不知道后来的某些变化是否会过时,这是一个完全正确和完整的模型.

  • 任何取决于我们理解为"正确"或"完整"的方法都是脆弱的.FTFY. (6认同)
  • 你的论证基本上是自然键,实际上,自然键不是好的自然键.获胜的重言式? (5认同)
  • 基于不正确或不完整建模的自然键是脆弱的.FTFY. (4认同)

nvo*_*gel 8

非常简单的答案是数据完整性.如果数据有用且准确,则可能需要密钥.具有"自动生成的id"也不会删除对其他键的要求.另一种方法是不强制执行唯一性并接受数据将被复制并且几乎不可避免地包含异常并导致错误.你为什么要那样?

  • 您可以强制实施唯一性,而不必将其作为主键.如果你有一个自然键和一个代理键,那么在自然键上不添加唯一索引就不好了. (4认同)
  • @HLGEM,关键是关键."主要"密钥与任何其他候选密钥之间没有区别.索引与它没有多大关系.密钥由*constraints*强制执行,而索引只是加速数据访问的一种方式. (4认同)

Joh*_*ohn 8

简而言之,组合键的目的是使用数据库来强制执行一个或多个业务规则.换句话说:保护数据的完整性.

防爆.您有从供应商处购买的零件清单.您可以创建供应商和零件表,如下所示:

SUPPLIER
SupplierId
SupplierName

PART
PartId
PartName
SupplierId
Run Code Online (Sandbox Code Playgroud)

哦,哦.零件表允许重复数据.由于您使用了自动生成的代理键,因此您不会强制执行供应商的零件只需输入一次这一事实.相反,您应该像这样创建PART表:

PART
SupplierId
SupplierPartId
PartName
Run Code Online (Sandbox Code Playgroud)

在此示例中,您的部件来自特定供应商,并且您希望强制执行规则:"单个供应商只能在PARTS表中提供一次".因此,复合键.复合键可防止意外重复输入零件.

您始终可以将业务规则保留在数据库之外并将其保留在应用程序中,但通过将规则保留在数据库中(通过组合密钥),可以确保业务规则在所有地方都得到强制执行,尤其是在您决定允许的情况下多个应用程序来访问数据.