为什么单个主键比复合键更好?

时间:2010-04-19 14:04:46

标签: database-design orm primary-key

为什么拒绝复合键有利于使用名为id的单个主键的所有表?因此通常所有ORM都遵循此原则。

修改

我刚开始在轨道上学习ruby,在实用的敏捷开发书中有一条线:--- 除非每个表都有一个数字主键,否则Rails确实不能很好地工作。对列的名称不太挑剔。 我在学习Doctrine时读到的那条线也一样。

EDIT2 请检查此链接。我对这件事越来越感到困惑:--- Composite primary keys versus unique object ID field

从以上链接: -

*主键应该是常量且无意义的;非代理键通常会失败一个或两个要求,最终

如果密钥不是常量,那么您将来会遇到更复杂的更新问题 如果密钥没有意义,那么它更有可能改变,即不是恒定的;见上文

举一个简单的常见例子:库存项目表。将项目编号(SKU编号,条形码,零件代码或其他任何东西)作为主键可能很诱人,但一年后所有项目编号都会发生变化,而且您将面临一个非常混乱的更新 - 整个 - 数据库问题...

编辑:还有一个比哲学更实际的问题。在许多情况下,你会以某种方式找到一个特定的行,然后再更新它或再次找到它(或两者)。使用复合键,有更多数据可以跟踪WHERE子句中的更多约束以及重新查找或更新(或删除)。在此期间,其中一个关键部分也可能已发生变化!使用代理键,始终只保留一个值(代理ID),根据定义,它不能更改,这可以显着简化情况。*

9 个答案:

答案 0 :(得分:23)

我认为没有一句话就是你应该只使用一个名为id的主键。

大多数人使用代理主键作为自动生成int,因为它将主键与需要更改的主键隔离开来,就像您将PK作为用户名并且后来更改了其合法名称一样。您必须更新PK和所有FK列以反映新名称。如果您使用了代理主键,则只需在一个位置更新用户名(因为表连接的是int而不是名称)。

主键的大小很重要,因为PK会复制到您在表上构建的每个索引中。如果PK很大(如字符串),则索引中每页的键数较少,索引将占用更多的高速缓存来存储它。 Ints很小。

拥有自动增量int PK有助于成为一个聚簇索引,因为行按此顺序存储,并且无需返回并阻止行插入新行,您总是添加到桌子的结尾。

答案 1 :(得分:13)

我使用复合键遇到的唯一真正限制是将IN表达式与子查询一起使用。这是一个问题,因为IN表达式中的子查询必须返回单个列(至少在T-SQL中)。

SELECT
    emp.Name,
    emp.UserDomain,
    emp.UserID
FROM
    employee emp
WHERE
    ???? IN (SELECT e.UserDomain, e.UserID FROM ... /* some complex 
                                                       non-correlated subquery 
                                                       or CTE */
            )

当然,总会有解决方法,但有时可能会令人烦恼。

这并不是在使用复合键的地方避免复合键的原因。

答案 2 :(得分:8)

您可以同时使用两者。在某些情况下,在实体之间建立关联时,您可以将两个实体键用作复合键。

根据经验,我使用生成的id作为实体,使用复合键作为关系。

答案 3 :(得分:5)

嗯,这基本上是关于保持JOIN简单 - 哪一个更容易理解:

SELECT
   p.ID, p.Name, p.City,
   c.ID, c.Country, c.ISOCode
FROM
   dbo.Parent p
INNER JOIN
   dbo.Child c on c.ParentID = p.ID

SELECT
   p.ID, p.Name, p.City,
   c.ID, c.Country, c.ISOCode
FROM
   dbo.Parent p
INNER JOIN
   dbo.Child c ON c.ParentName = p.Name
     AND c.ParentCity = p.City
     AND c.ParentCountry = p.Country

如果您有复合主键,那么从子表连接到您的表的任何人都必须“拖动”所有这些列,并且所有这些列也将出现在子表中,并且JOIN语句非常混乱。为JOIN创建一个(甚至是代理)密钥要好得多!

答案 4 :(得分:3)

我使用11列主键处理了一个应用。每次我想要保证我更新一行时,重复输入列表总是非常有趣。它是bug的驱动因素,MS-Access无法应对PK等10多个列。

大型复合键是设计气味,意味着表格包含异构实体,或者设计师并不确定每个实体的独特之处。 (就像假设头发的颜色,眼睛的颜色和体重应该足以唯一地识别一个员工 - 这不是一个好的关键,因为你需要越来越多的专栏来使它发挥作用,最终将包括字段那些挥发性和变化很大,如重量,或者某些人的头发颜色或缺乏。)

答案 5 :(得分:2)

虽然我同意其他受访者给出的大多数理由,但我更喜欢单列整数键的主要原因是它使编写用户界面变得更加容易。

如果使用某种列表控件来表示数据(列表,列表视图,组合框等),则可以通过与项目一起存储的单个整数值将每个条目唯一地关联回其数据库表示。大多数预先编写的组件已经允许您为每个项目附加一个整数,对于那些没有的项目,可以很容易地扩展组件来实现这一点。

如果您在服务器应用程序和网页之间传递数据,那么将单个标识值存储在代表数据的窗口小部件的id属性中要比组合和解析多值ID更容易

答案 6 :(得分:1)

  1. 对于ORM单一识别 具有一致名称的列 table_id比复合更容易 键。但每个良好的ORM支持 复合键。

  2. 简单的PK很容易 数据库'自动增加'。 这不适用于复合材料 键。

  3. 简单的PK也更容易使用 查询。当你需要加入时,你 只需要使用两列中的一列 关系。

  4. 这并不是说简单的PK比复合的更好。

答案 7 :(得分:0)

OO编程中的对象无论其内容如何都具有身份。关系数据库中的行(元组)仅由其内容标识。因此,当真正进行ORM时,即将对象从面向对象的编程语言映射到关系数据库时,必须提供额外的ID,以区别于对象在程序中的字段和/或属性 - 除非其中一个或多个是以某种方式知道唯一地识别对象。

答案 8 :(得分:0)

您的问题与surrogate (or artificial) keys vs natural keys替代方案密切相关。我认为并不是复合键的使用较少,但自然键(无论是复合键还是简单键)都不如人工键更受青睐。

传统的关系数据库理论主要处理“自然”密钥(从业务领域的角度来看具有意义的密钥),在这种情况下,复合密钥经常被发现......自然而然。

但在后来的几年中,数据库设计一直倾向于(虽然不是唯一的)“人工”(代理)密钥模式,通常是一个没有商业意义的序列号,只用于唯一标识表中的记录(和也许是上层的对象)。