【问题标题】:Can I have too many columns in my composite primary key on one table我可以在一张表上的复合主键中有太多列吗
【发布时间】:2016-07-15 15:34:09
【问题描述】:

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

--

我的 3 个表是员工、培训和 emp_training。雇员表保存雇员数据。培训表可容纳不同的培训课程。我正在将 emp_training 表设计为字段 EmployeeID (FK)、TrainingID (FK)、OnDate。

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

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

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

我在使用 2 个字段作为主键之前创建了很多表,但从来没有使用 3 个,所以我很好奇继续使用选项 A 是否有任何缺点

【问题讨论】:

  • 那里,我修改了你的标题。我想这就是你的意思。
  • 还有一点(除了下面的答案):您的但他们不能在同一天多次参加同一培训课程是一个反对PK:这不是绝对的规则,只是一种业务逻辑。如果有一种情况,同一门课一天可以上两次,你会怎么做?那你会怎么做?

标签: mysql sql-server database ms-access


【解决方案1】:

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

您可以定义一个新的聚集索引不是 PK。 “主键”其实只是一个名字……

最重要的问题是:哪些列参与了聚集键以及(这是最重要的问题):它们是否具有隐式排序?并且(也很重要):是否有很多更新操作会改变参与列的内容?

您必须知道,集群键定义了硬盘上的物理顺序。换句话说:聚集键就是表本身。您可以考虑包含所有列的索引。如果您的前导列(最坏情况)是一个 GUID,则每次插入到您的表中都将不按顺序进行。这会导致 99.99% 的碎片化。

如果聚簇索引绑定了插入时间或运行数(最佳情况),则永远不会分片!

更糟糕的是:如果有一个聚集键(无论它是否称为 PK),它将被用作其他索引的查找键。

所以:在许多情况下,最好使用运行数字作为聚集键和非聚集多列索引,这样重建起来比使用聚集索引要快得多。

所有索引都将从中受益!

我给你的建议:

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

【讨论】:

  • 旧线程但关于集群键最重要的声明在这里
【解决方案2】:

是的,如果可以通过二级索引采用更好的策略来实现唯一性,那么您可能为复合主键 (PK) 选择过多列的策略不佳。

请记住,PK 是特殊的。您的数据只有 1 个物理/集群排序。通过插入和更新(以及现有的改组)对数据进行的更改会产生开销,如果在二级索引中维护这些开销就不会存在。

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

  1. 具有 5 个复合列的主键

对比

  1. 具有 1 或 2 列加的主键
    • 如果经过深思熟虑,可以保持唯一性的二级索引

前者要求在数据页之间移动数据以维护聚集索引 (PK)。这可能说明了为什么人们经常看到:

(
id int auto_increment primary key,
...
)

在表格设计中。

索引宽度的性能:

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

FK 组合案例:

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

【讨论】:

    【解决方案3】:

    我认为创建具有组合 PK 的表没有任何问题,在较大的数据库中需要此类表。创建具有 2FK 的表并没有真正的问题,其 OnDate 字段形成 PK。两种方式都可以。 祝你好运!

    【讨论】:

    • 比问题更重要的是一个 PK 可能由许多列组成吗? 问题是 此索引是否已聚集,参与的列是否已隐式排序? .错误的聚集索引也会减慢所有其他索引,因为它充当它们的查找键...
    【解决方案4】:

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

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

    training、emp_training、OnDate 一起会有唯一记录,不能一起为空。

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

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

    【讨论】:

    • 您应该永远创建没有名称的 PK(或任何其他约束)!使用CONSTRAINT PK_employee PRIMARY KEY(training,emp_training,OnDate)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-11
    • 2020-10-02
    • 2010-12-17
    • 2019-02-19
    • 2014-01-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多