我应该何时使用复合主键?

时间:2015-07-11 19:11:48

标签: database-design composite-key

ETA:我的问题是基于保持最佳数据库。具有 ProjectUserBooleanAttribute 的所有复合主键的数据库性能/大小有何不同,后者可能具有 PUAT_Id UserID 的索引,以及一个非复合表,使用自动增量PK,但后面有 PUAT_Id UserID 的索引?从进一步阅读看来,如果我采用非复合方法,我将不得不在这两列上创建一个唯一索引。我还需要在这两列上创建索引吗?如果是这样,这实际上是否意味着该表中的每一列都有自己的索引?

这是数据库大小(索引)与性能的典型困境吗?

所以我想要创建以下实体

  • 项目
  • 用户
  • ProjectUserAttributeTypes

在这个简化示例中,我的所有ProjectUserAttributeTypes都将是 boolean ,所以我只显示 ProjectUserBooleanAttribute 表。

假设我要创建两个名为 Silver Gold 的布尔ProjectUserAttributeType。我只想在 ProjectUserAttributeTypes 中创建两行。现在,如果我想将用户指定为具有该属性,我会在 ProjectUserBooleanAttribute

中添加一行

出于性能原因,DBA已经警告我不要使用复合主键。然而在这种情况下,我没有看到我使用复合材料获得了什么。在这两种情况下,我都需要确保 ProjectUserBooleanAttribute 具有所有列的非null和唯一值。我当然也需要索引。

注意:我的最终目标是能够查询我的数据库并查找具有某些属性组合的所有用户。我会加入表来按项目过滤,然后使用where子句进一步过滤。几个例子:

  • (金或银)
  • (GOLD XOR SILVER)
  • ((金或银)而非(铜))

COMPOSITE PK

Compsite ERD

非复合PK

No Composite ERD

2 个答案:

答案 0 :(得分:14)

关系数据库有两种主要设计:

  • 自然键
  • 的ID

使用自然键,您可以使用给定的键:项目由项目编号标识,用户通过登录名或编号标识等。这通常会导致复合(或复合)键:

  • 项目( project_no ,名称,......)
  • 用户( user_name ,first_name,last_mname,...)
  • project_user( project_no,user_name ,角色,...)

表project_user有一个复合键:项目编号加上唯一标识记录的用户名,告诉我们谁正在处理哪个项目。

使用ID,您通常会添加一个技术ID,该ID仅用于链接记录,对用户没有任何意义:

  • 项目( project_id ,project_no,name,...)
  • 用户( user_id ,user_name,first_name,last_mname,...)
  • project_user( project_user_id ,project_id,user_id,role,...)

这些表包含相同的字段和ID,您需要与自然键和ID上的约束相同的唯一且非空约束。

当有任何需要该引用的表时,project_user中的project_user_id当然是必需的。但通常每个表都会获得一个ID,无论是否需要,只是为了使它们看起来都相似(所以ID已经存在,以防以后需要它们。)

乍一看,似乎基于ID的数据库只是更多的工作,更多的索引和没有获得,但事实并非如此。通常选择ID概念,因为它提供了更多自由。一个例子:如果项目编号可以改变,会发生什么?使用自然键,项目编号在许多表中,并且必须以某种方式级联更新,这可能成为一项非常重要的任务。在ID数据库中,您只需在一个位置更改项目ID。

如果突然项目编号在公司内部是唯一的,那么帽子会发生吗?在基于ID的数据库中,您可以将company_id添加到项目表中,在company_id和project_no上添加唯一索引并完成它。使用自然密钥,必须将公司编号(ILN?人工编号?)添加到主密钥中,并且必须在所有子表中引入。所以:当你使用自然键设计一个数据库时,你必须全力以赴地获得稳定的自然键 - 有时候没有,然后你必须发明一些。使用ID,您不必关心字段是否可以更改。因此,基于ID的数据库更容易实现。

然后是层次结构。假设您的数据库中有几家公司,每家公司都有自己的项目,拥有自己的仓库。

自然键:

  • 公司( company_code ,名称,......)
  • 项目( company_code,item_no ,名称,...)
  • 仓库( company_code,warehouse_no ,地址,......)
  • stock( company_code,warehouse_no,item_no ,金额,......)

的ID:

  • 公司( company_id ,名称,......)
  • 项目( item_id ,item_no,name,company_id,...)
  • 仓库( warehouse_id ,地址,company_id,...)
  • 库存( stock_id ,仓库_商品,商品数量,商品数量......)

使用ID概念,您不必在stock表中再次命名company_id,因为它是从父表中获知的。存储它甚至是多余的,而在自然键概念中它是必需的,因为它是复合键的一部分而没有它我们将失去与其父表的链接。有些人认为这种纯度是ID概念优于自然键的一大优势。然而,它有一个缺点。在自然密钥数据库中,保证公司的物品在公司的仓库中,因为公司是库存表的关键的一部分。使用ID概念,链接的仓库记录可能属于公司1,链接的项目记录可能属于公司2.由DBMS无法阻止我们的错误插入语句导致的数据不一致。使用自然键不会发生这样的错误。

如果我想知道一家公司有多少股票,我只需从自然键中选择股票。但我必须从股票和另一张表中选择将公司放入ID数据库。

如果数据库是基于ID的,那么在层次结构很多的情况下,您可能会获得包含许多表的查询。到目前为止,我还没有看到基于ID的数据库优于使用自然键的数据库。但到目前为止,我已经看到基于自然密钥的数据库优于基于ID的数据库。这可能是因为我主要看到有很多层次结构的大型数据库。

关于您的数据库:它似乎是基于ID的,前提是项目ID和用户ID只是技术内部数字 - 否则您的数据库将是一个混合概念(自然项目编号,自然用户ID,ProjectUserBooleanAttribute的技术ID)。所以你的问题与复合键没有关系。

PUAT_ID和UserID都必须在ProjectUserBooleanAttribute中,它们不是null,并且您应该对它们有唯一约束(唯一索引)。因此,无论你是否称之为“主键”,它们都具备所有品质的主要需求。或不。是否添加技术ID只是为了它的外观。它并没有真正改变任何事情。这个概念保持不变。

在自然键概念中,您可以将字段作为主键。但是,你不会有PUAT_Id,而是一些复合键(ProjectId加上AttributeType?)。

在技术ID概念中,您不会将其作为主键,但要使字段不为空并添加唯一约束(这使其成为键,只有它不被调用" primary")。然后添加技术ID作为主键或使表没有ID,因此没有主键。这没关系。如果有人要求钥匙,请给他们身份证,如果没有,你可以不用它。只要任何其他表都不需要,它就是多余的。

答案 1 :(得分:0)

当您向表中添加id列时,它不可避免地增加了管理该表的开销。但好处是其他表现在可以通过单个id列而不是旧的复合键来引用该表的行。这可以使存储和索引更小,并且可以更快地访问这些表。此外,它可以更简单地引用相应的实体(只有一列),更明显(通过id的类型)。

请注意,在现在使用添加的id作为FK的表中,如果保留任何旧的复合FK列以及id,那么您应该有一个约束,即这些列的值与这些列的值相同id引用的行中的列。