例如,我有2个表,Users
和UserRelations
,这是一对多的关系。
对于UserRelations
表,我可以拥有一个标识列并将其作为主键:
[RelationID] [int] IDENTITY(1,1) NOT NULL,
[UserID] [int] NOT NULL,
[TargetID] [int] NOT NULL,
或者我可以设计表格如下:
[UserID] [int] NOT NULL,
[TargetID] [int] NOT NULL,
并将UserID
+ TargetID
作为主键。
我的问题是每种设计的含义是什么,哪种性能更好?
答案 0 :(得分:9)
如果使用以前的设计,使用多余的标识列,则不存在插入具有相同UserID和TargetID的两行的约束。您必须在其他两列上创建UNIQUE
约束,无论如何都会创建一个复合索引。
另一方面,一些框架(例如Rails)坚持认为每个表都有一个名为id
的代理键,因此“正确”的设计可能不起作用。这取决于您使用此表设计编写的代码。
答案 1 :(得分:7)
这几乎是一个宗教问题。对于每个使用非智能代理键的人,有人指出代理键可以被认为是多余的,等等。所以做对你和你的团队来说最舒服的事情。
如果您决定使用代理键,则还应在自然(在本例中为多列)键上设置唯一约束,以保持数据的完整性。
我通常会寻找额外的代理键,因为自然键有时会缺少一些理想的(不一定是必需的)主键特征:
从性能的角度来看,我怀疑大多数情况下差别不大。但与任何性能问题一样,您应该衡量您所关注的问题。
答案 2 :(得分:3)
据我所知(实际上,实际上它很有意义),主键识别一些独特的数据......至少在标准化表中。如果表中的数据需要通过密钥更明确地标识,则应使用复合主键(其中包含多个列的主键)。
例如,在一个存储当前和过去约会的表格中,客户可以多次出现在表格中,您可以设置如下表格:
AppointmentDate,CustomerID,AppointmentReason
AppointmentDate和CustomerID是复合主键,并标识AppointmentReason的唯一信息。
我们同时使用AppointmentDate和CustomerID作为主要复合键,因为多个客户可以在同一天同时进行约会。如果我们只使用一个AppointmentDate作为主键,我们可能会遇到主键上唯一性约束的问题。
对于您的情况,有助于获得有关将包含哪种数据的更多信息,但是我可以将UserID和TargetID作为复合主键以及TargetID是UserRelations表的外键(如果它出现)在您的用户表中。我这样做是因为如果你有一个名为RelationID的主键,你最终会得到一个重复的用户列,这可能会对性能产生负面影响,并且根本不会使你的表正常化。
答案 3 :(得分:2)
您“应该”始终尝试在每个表上建立“有意义的”或“自然的”主键或唯一索引,以帮助维护数据的完整性。当这意味着一个多列(或“复合”键)时,确实存在性能影响 - 特别是当使用相同的多列键作为其他从属表中的外键,或者在查询中用于搜索谓词的索引等时。 。
当这些性能影响变得显着时(甚至可能在他们这样做之前),您应该切换到使用无意义的“代理”密钥(通常是整数),用于所有其他目的(FK,联接,指数,查询搜索谓词,应用程序代码实体Identifers等。)
但始终保留有意义的密钥或唯一索引,以维护表数据的完整性
答案 4 :(得分:2)
就性能而言,通过对描述关系的表使用复合主键,我获得了良好的结果。声明主键有两种效果:
您获得的约束要求每个参与列都是非空的,并且需要参与列的唯一性。
在获得主键的情况下,您将获得一个可快速访问单个行的索引。大多数DBMS都会为您创建此索引。
此索引的有用性取决于查询优化程序,主键声明中列的顺序以及数据的使用模式。有时,通过您自己创建的索引来补充自动索引,在复合主键中第一个以外的列上补充自动索引会很有用。
通过声明复合主键获得的约束通常比通过创建代理键并声明主键更有用。
同样,所有上述内容都涉及描述实体之间或之间关系的表。描述实体的表应该有一个简单的主键。优选地是自然密钥,但是在给定数据不提供可靠密钥的情况下,可能需要代理密钥。
答案 5 :(得分:1)
主键是索引与唯一性约束的组合。添加RelationID列将无法帮助您保持唯一性(因为仍然可以插入相同的UserID + TargetID对 - 它们将获得不同的RelationID),也不会帮助进行数据访问(如果您将在用户之间加入,则需要在UserID上建立索引和UserRelations)。所以第二个似乎是更好的解决方案。
答案 6 :(得分:1)
为了搅拌锅,你可能需要第三列:“关系”。任何时候我都有一个用户:用户关系表,我遇到了两个拥有多个关系并需要将它们分开的用户:
David Jeff Mentor
David Jeff Sponsor
在某些时候,指导可能会结束,但您仍然需要赞助商链接。虽然现在可能只有一种关系类型,但将来可能会改变。因此,您的主键变为UserId,TargetId,RelationshipType。
答案 7 :(得分:1)
我要在这里抛出我的两分钱,因为我相信在其他答案的组合中有一个格式塔没有清楚地呈现。
答案 8 :(得分:0)
假设您使用UserRelations表在用户和目标之间进行多对多关系,则第一个关系不正确。您希望UserID + TargetID是唯一的,否则您最终可能会有多个冗余条目加入同一个用户和目标。
答案 9 :(得分:0)
关联用户的适当方法 - >目标是您拥有的第二个选项,因为这是实际强制执行查找表的引用完整性的方法。
如果没有主键,或者在UserId和TargetId列中没有主键,则可能会有重复的条目,这很可能会导致意外的结果。
答案 10 :(得分:0)
特别针对您的问题:在任何情况下,您都需要在自然多列上使用唯一键。是否让它成为主要由你决定。
添加代理键是一种样式问题,并且通常需要某些框架。如果你添加它,在大多数情况下使它成为主要的,只是因为这是框架所期望的。从功能上讲,只要两者都是独一无二的,否则没有区别。