具有限制的多对多关系的数据库设计

时间:2015-07-24 22:44:02

标签: sql database-design sqlperformance

我有一个用户数据库和一个有问题的数据库。我想要的是确保每个用户只能回答一次问题。

我想到了一个数据库,它将所有问题ID作为列,所有用户ID都作为记录,但当问题和用户数量时,这会变得非常大(而且速度很慢)增长。

还有另一种方法可以提高性能吗?

2 个答案:

答案 0 :(得分:3)

你可能想要这样的设置。

Questions table (QuestionID Primary Key, QuestionText)
Users table (UserID Primary Key, Username)
Answers table (QuestionID, UserID, Date) -- plus AnswerText/Score/Etc as needed.

Answers表中,两个第一列一起形成复合主键(QuestionID, UserID),两者分别是Question(QuestionID)Users(UserID)的外键。

复合主键确保QuestionID/UserID的每个组合仅允许一次。如果您想允许用户多次回答同一个问题,您可以扩展“复合主键”以包含日期(它将是复合键)。

这是一种标准化设计,应该足够高效。通常使用surrogate primary key(如AnswerID)而不是复合键,并使用unique约束来确保唯一性 - 使用代理键通常是因为易于使用,但这绝不是必要的。

答案 1 :(得分:2)

下面是我自己的表格设计图,非常类似于jpw的correct Answer。我编写了几个列名,以更好地了解表的性质。我使用了Postgres个数据类型。

正如该答案的最后一段所讨论的那样,我会在response_(“答案”)表格中使用简单的单一主键,而不是将fkey_user_&组合成一个复合主键。 fkey_question_

ERD diagram of three tables

不切实际

此图符合问题中的问题描述。然而,这种设计是不切实际的。这种情况是针对一组问题提供给用户,只进行一次调查或测验。在像学校,民意调查或焦点小组这样的情况下的现实生活中,我希望我们会向用户提交一份以上的调查问卷。但我会忽略这一点,直接以措辞来解决问题。

同样在某些情况下,我们可能会有一个问题的版本,因为它会在连续的测验/问卷调查中随着时间的推移进行调整和修订。

性能

您的问题正确地将此问题标识为用户与问题之间的多对多关系,其中每个用户可以回答许多问题,并且每个问题可能会被许多用户回答。在关系数据库设计中,只有一种表示多对多的正确方法。这种方式是添加第三个子表,有时称为“桥表”,外键链接到两个父表中的每一个。

在一个图表中,您将父表垂直地向上绘制在页面上方而不是子表,我个人看到这样的多对多图表是蝴蝶或鸟图案,其中子桥表是身体/胸部和两个父母是翅膀。

在某种意义上,性能是无关紧要的,因为这是唯一正确的设计。幸运的是,现代关系数据库针对这种情况进行了优化。您应该会看到数百万条记录的良好表现。特别是如果您将序号作为主键值。我倾向于使用UUID数据类型;当表大小达到数百万时,它们的任意位值可能具有较低的索引性能(但我不知道细节。