我可以在一个表上的复合主键中包含太多列

时间:2016-07-15 15:34:10

标签: mysql sql-server database ms-access

我有一个使用2个外键字段和日期字段的表。 让表使用3个或更多字段作为主键是否常见?这样做有什么不利之处吗?

-

我的3个表是员工,培训和培训。 employees表包含员工数据。培训表包含不同的培训课程。我正在将emp_training表设计为EmployeeID(FK),TrainingID(FK),OnDate字段。

员工可以参加多个培训课程,可以多次进行相同的培训课程。但他们不能在同一天多次参加相同的培训课程。 哪个更好实施:

选项A - 将所有3个字段设为主键

选项B - 添加自动编号PK字段,并使用查询查找任何可能的重复项。

在使用2个字段作为主键之前我已创建了许多表,但从未创建过3个,所以我很好奇是否有任何不利于继续选项A

4 个答案:

答案 0 :(得分:2)

是的,如果通过二级索引可以通过更好的策略获得唯一性,那么 可能选择太多的复合主键(PK)列。

请记住PK很特别。您的数据只有1个物理/集群排序。通过插入和更新(以及现任洗牌)对数据的更改会产生开销,如果在二级索引中维护则不会存在。

所以以下内容可能没有那么微不足道的差异:

  1. 包含5个复合列的主键
  2. VS

    1. 包含1或2列的主键
      • 如果仔细考虑,则保持唯一性的二级索引
    2. 前者要求数据页之间的数据移动以维护聚簇索引(PK)。这可能表明为什么经常会看到:

      (
      id int auto_increment primary key,
      ...
      )
      

      在表格设计中。

      索引宽度的效果:

      上面1中PK的宽度很窄。宽度为2.可以很宽。传播到子关系的更广泛的密钥会降低性能和并发性。

      FK成分的案例:

      如果不使用单列索引,最好是PK,就不能实现外键组合的特殊情况,如我最近的Answer所示。

答案 1 :(得分:1)

我不认为创建具有组合PK的表存在任何问题,在较大的db中需要这样的表。在创建具有2DK的表时没有真正的问题,其中OnDate字段形成PK。这两种方式都是可用的。 祝你好运!

答案 2 :(得分:1)

如果在多个列上分配主键,则它将是复合主键。例如,

CREATE TABLE employee(
  training VARCHAR(10),
  emp_training VARCHAR (20),
  OnDate INTEGER,
  PRIMARY KEY (training, emp_training, OnDate)
)

训练中会有独特的记录,emp_training,OnDate在一起,不能一起归零。

如前所述,您可以拥有一个由多列组成的主键。

如果问题是如何单独制作列主键,那就不可能了。但是,您可以创建1个主键并添加两个唯一键

答案 3 :(得分:1)

值得一提的是,对于SQL Server,默认情况下PK是唯一的群集密钥,但您也可以创建非群集PK。

您可以定义新的聚集索引,而不是PK 。 "主键"实际上只是一个名字......

最重要的问题是:哪些列参与了群集密钥(这是非常重要的问题):他们是否有隐式排序?而且(非常重要):是否有许多更新操作会更改参与列的内容?

您必须知道,群集密钥定义了硬盘上的物理顺序。换句话说:群集密钥是表本身。您可以考虑包含所有列的索引。如果您的主要列(最差情况)是GUID,则表格中的每个插入都不会按顺序。这导致99.99%的碎片化。

如果聚集索引绑定到插入时间或正在运行的数字(最佳情况),它将永远不会进入碎片!

更糟糕的是:如果存在群集密钥(无论是否称为PK),它将被用作其他索引的查找密钥。

所以:在许多情况下,最好使用一个正在运行的数字作为聚簇密钥和一个非聚集的多列索引,它比重新构建聚簇更快,就好像它是聚簇索引一样。

所有索引都将从中受益!

我的建议:

  • 选项C:作为PK的运行编号,另外还有一个唯一的多列密钥,以确保数据的完整性。这里不需要使用自己的逻辑......