外键是否应成为表主键?

时间:2010-03-30 14:20:19

标签: database primary-key foreign-keys

我有一个表(session_comments),其中包含以下字段结构:

student_id (foreign key to students table)
session_id (foreign key to sessions table)
session_subject_ID (foreign key to session_subjects table)
user_id (foreign key to users table)
comment_date_time
comment

现在,student_id,session_id和session_subject_id的组合将唯一地标识该学生对该会话主题的评论。

鉴于它们是独一无二的,即使它们是外键,我是否有优势使它们成为该表的组合主键?

再次感谢。

6 个答案:

答案 0 :(得分:14)

  1. 将它们作为主键将强制唯一性(而不是暗示它)。
  2. 主键可能是群集的(取决于dbms),这将提高某些查询的性能。
  3. 它节省了添加唯一约束的空间,在某些DBMS中也创建了唯一索引。
  4. 无论您是否将这三个作为主键,您仍然需要某种唯一性约束来保证学生不能与同一会话和session_subject_id关联两次。如果允许该方案,则需要将唯一性约束扩展为包含另一列。

    无论你做出什么选择,你都应该在桌面上有某种独特性限制。

    如果您正在讨论是否在三列上创建代理主键+唯一约束,我会说这取决于该表是否具有子表。如果可以,那么引用代理键将更容易和更小。如果它不会,那么IMO,代理键并没有真正给你太多,你也可以使用三列作为PK。

答案 1 :(得分:6)

这取决于应用程序的其余部分 如果您不打算在评论表中显示外键(这似乎很可能),这很好 如果您需要引用另一个表中的注释,最好使用3个字段创建一个唯一索引,再加上一个 AutoNumber 主键,该主键将作为外键在其他表中提供(比3个领域更简单,更便宜。

答案 2 :(得分:3)

自然与人工密钥的争论与任何数据库实现一样古老。 在wikipedia上阅读有关专业人士和骗子的信息。

代理键的争论很容易在理论层面上受到争议(例如,使用自然键可能会导致PK变得非独特的风险可以与答案反驳 - 好!如果我遇到这种情况它事情会好坏,而不是人为地拥有唯一的主键,并且有实际数据的重复记录。)

另一个好的论据是人工密钥要么是冗余的(表上有另一个唯一的密钥),要么它们允许您存储基本上非唯一的记录。

尽管如此,找到好的自然键有时是如此困难以至于你必须选择一些人为的东西,并允许你有一个同名的人,出生在同一个日期(或者日期不详),另一个xy属性的情况价值相同。

此外,还不是很清楚什么是人造的,什么是自然的。 例如,您可能会说SSN对您的数据很自然。即使它真的是数字。

至于多键关系的表现 - 这些并不像你想象的那么糟糕 - 此外 - 它以自然的方式对索引进行分段,并且使用这样的键,你通常会得到一个与普通表现非常相似的数据库没有任何附加索引的查询。

如果您认真考虑这些问题并且如果您正在尝试构建复杂的系统,请阅读一些好的文献(C.J.Date数据库系统简介,目前在第8版中出现)

答案 3 :(得分:2)

我真的建议您使用由您选择的数据库为您生成的主键。主要是因为如果您在将来维护期间更改该表的结构,那么您将面临唯一密钥变为非唯一的风险。这可能是一个非常棘手的问题。还有一个唯一的主键使查询表更加容易。

postgres的唯一ID:http://www.postgresql.org/docs/8.1/interactive/datatype.html#DATATYPE-SERIAL

Mysql的唯一ID:http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html

答案 4 :(得分:2)

将它们变成复合主键的唯一原因是每个学生/会话/主题强制执行一个注释。假设您不想这样做,我不会创建另一个密钥。

答案 5 :(得分:1)

没有。 FOREIGN键可以包含在PRIMARY键中不允许的NULL。您可以做的最好的事情是从列创建一个UNIQUE索引。

在表格上创建一个PRIMARY键。

回应:我的下一个问题是: 4个表中的键之间是否有重叠的可能性?

这两个会创建101010101的相同复合键: 学生:1010,课程:10,科目:10,用户:1 学生:10,课程:1010,科目:10,用户:1

我只是指出,四个列应该有明显不同的域重叠,以减少可能性。

可能最好使用真正的主键。