将4列作为主键是否合适?

Int*_*aoi 7 sql t-sql sql-server

我在我的数据库表中Students有PK Student_ID,带PK的课程Course_ID.

并且有两个表来保存每个课程的反馈结果,表格Questions我保存在PK的反馈问题中question_ID,以及表格反馈.

我想知道如果我能在反馈表中使用的3个外键(course_ID,student_Id,question_ID)与PKfeedback_ID

我认为为每个问题或学生或课程提供结果是有用的,但我不知道是否可以使用4列作为主键和好或不好.

Sql*_*Zim 5

因为大多数人都认为主键是聚类键,所以我将您的问题解释为“有4列作为聚类键是好是坏”。

您正在考虑的情况与诸如聚集索引辩论代理密钥与自然密钥之辩论有关。

在这种情况下,我想考虑12字节宽的复合群集密钥与4字节宽的群集密钥(如果要使用的话,则加倍bigint)的影响。我的决策树如下所示:

  1. 我们将使用Hekaton(内存中OLTP)吗?

    • 是=>复合键。逃走

    • 否=>好的电话,继续...

  2. 该表将有几行?

    • 数千万,也许更多!=>代理密钥(可能是)。

      • 如果每行的数据长度是可变的并且不是窄的=>代理键。

      • 如果该行的数据长度是固定且狭窄的,从而导致最佳的页面使用率=>继续...

    • 小于等于=>继续...

  3. 如何查询反馈表?

    • course_id, student_Id, question_id=>替代键的各种组合(并非总是)。

      • 在这种情况下,您可能希望能够有多个支持索引,以及course_id, student_Id, question_id针对您的查询的组合。集群键包含在所有非集群索引中,并且越大,每个索引条目将需要的空间/页越多。=>代理密钥。
    • 几乎总是三者course_id, student_Id, question_id或几乎总是由course_idcourse_id, student_Id; 但不是student_id没有course_id而不是question_id不是course_id, student_id(这个表上零或只有几个非聚集索引)=>继续...

  4. 其他表格会引用该表格吗?

    • 是:例如,课程指导员将能够对反馈问题的回复发表评论或评论。=>代理密钥。

    • 种类...例如,审核/历史记录表将跟踪对该表中行的插入/更新/删除。

      • 代理密钥可能会使更改跟踪的审核变得不太复杂,并且审核表的群集密钥很可能是代理密钥和日期时间或代理密钥与复合密钥和日期时间或代理密钥。
    • 否=>复合键是一个合理的选择


即使我首先经历了以上决策树,但是我还是会使用替代键来开始设计,因为摆脱它(因为未被使用)比回去要容易得多。并添加它并实现其使用。

只是为了澄清一下,我确实发现组合键是更好的解决方案,并且确实重构了设计以删除代理键。我不想留下代理密钥始终是更好的解决方案的印象,即使它是许多设计师(包括我自己)的常见默认设置。


我将从以下内容开始:

create table feedback (
    feedback_id    int       not null identity(1,1)
  , course_id      int       not null
  , student_id     int       not null
  , question_id    int       not null
  , response_added datetime  not null
      constraint df_feedback_response_added_gd default getdate()
  , response       nvarchar(max) null
  , constraint pk_feedback primary key clustered (feedback_id)
  , constraint fk_feedback_course   foreign key (course_id)   
      references course(course_id)
  , constraint fk_feedback_students foreign key (student_id)  
      references student(student_id)
  , constraint fk_feedback_question foreign key (question_id) 
      references question(question_id)
  , constraint uq_feedback_course_student_question 
      unique (course_id, student_Id, question_id)
   /* or create a unique index to use include() instead */
  );

  /* unique index that includes response */
  create unique nonclustered index ux_feedback_course_student_question_covering
      on feedback (course_id, student_Id, question_id) 
        include (response_added, response);
Run Code Online (Sandbox Code Playgroud)

参考: