我的数据库表格Students
包含PK Student_ID
,课程包含PK Course_ID
。
两个表格用于保存每个课程的反馈结果,表Questions
我保存在PK question_ID
的反馈问题和表格反馈中。
我想知道我是否可以使用PK course_ID
student_Id
,question_ID
,feedback_ID
)中的3个外键
我认为为每个问题或学生或课程提供结果很有用,但我不知道是否可以使用4列作为主键,不管是否好。
答案 0 :(得分:3)
如果Feedback_Id
唯一标识记录,那么将其作为主键应该可以正常工作。在PK中包含多个列可能会在将来造成麻烦。
让我们说你想坚持其他反馈细节(比如评论)。您想要定义一个名为FeedbackComment的表,该表应将Feedback作为父级。 FK只能转到一个或多个定义了UNIQUE约束的列。通常,PK是PK的目标。
当然,您可以在子表中定义PK的所有列(feedback_id,course_id等),但这会使连接更复杂。
此外,如果您在应用程序的服务层中使用某种ORM(即实体框架),则使用单个整数主键可能很有用(例如,具有基于整数标识符检索实体的泛型方法)。
正如戈登所说,复合主键没有任何问题,但考虑一下你对表的处理方式,而不是在必须进行应用程序扩展时使你的生活复杂化。
答案 1 :(得分:3)
由于大多数人认为主键是群集密钥,因此我将您的问题解释为“将4列作为群集密钥是好还是坏”。
您正在考虑的情况与The Clustered Index Debate和Surrogate Key vs. Natural Key等辩论有关。
在这种情况下,我想考虑12字节宽复合群集密钥与4字节宽群集密钥的影响(如果您要使用bigint
,则为两倍)。我的决策树看起来像这样:
我们会使用Hekaton(内存中OLTP)吗?
是=>复合键。 Run away.
否=>好的电话,继续......
此表有多少行?
数千万,甚至更多! =>代理键(可能)。
如果每行的数据长度是可变的而不是狭窄的=>代理关键。
如果行的数据长度固定且缩小,则会导致页面使用最佳=>继续...
小于那个=>继续...
如何查询反馈表?
course_id, student_Id, question_id
=>的各种组合,并非总是如此。代理关键。
course_id, student_Id, question_id
的组合。
聚簇键包含在所有非聚簇索引中,并且它越大,每个索引条目将需要的空间/页面越多。 =>代理钥匙。几乎总是由所有三个course_id, student_Id, question_id
或几乎总是由course_id
或course_id, student_Id
;
但不是student_id
没有course_id
而不是question_id
没有course_id, student_id
(此表上只有几个非聚集索引)=>继续...
其他任何表都会引用此表吗?
是的:例如课程讲师将能够就反馈问题的回答发表评论或评论。 =>代理关键。
有点......审计/历史记录表将跟踪此表中行的插入/更新/删除。
否=>复合键是一个合理的选择
即使我第一次运行上面的决策树导致我使用复合键,我可能会使用代理键开始我的设计,因为它更容易摆脱它(因为它没有被使用)返回并添加并实现其使用。
为了澄清一下,我遇到了一些案例,我确实发现复合键是一个更好的解决方案并且重构了设计以放弃代理键。我不想留下代理键始终是更好的解决方案的印象,即使它是许多设计师(包括我自己)的常见默认设置。
我会从这样的事情开始:
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);
参考: