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

Database design for many-to-many relations with restrictions

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

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

是否有另一种性能更好的方法?

您可能想要这样的设置。

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

Answers table 中,前两列一起形成一个复合主键 (QuestionID, UserID) 并且它们分别是 Question(QuestionID)Users(UserID) 的外键.

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

这是一个规范化的设计,应该足够高效。通常使用 surrogate primary key(如 AnswerID)代替复合键并使用 unique 约束来确保唯一性——代理键的使用通常是出于易用性的考虑, 但绝对没有必要。

图表

下面是我自己table设计的图,和 by jpw. I made up a few column names to give more of a flavor of the nature of the table. I used Postgres数据类型很相似。

正如该答案的最后一段所讨论的那样,我会在 response_ ("Answers") table 上使用一个简单的单一主键,而不是组合主键 fkey_user_ & fkey_question_.

不切实际

此图符合问题中的问题描述。然而这种设计是不可行的。此场景适用于向用户提出一组问题,永远只有一个调查或测验。在学校、民意调查或焦点小组等现实生活中,我希望我们会向用户提供不止一份问卷。但我会忽略它直接解决问题的措辞。

此外,在某些情况下,我们可能会有问题的版本,因为在连续 quizzes/questionnaires.

给出时,它会随着时间的推移进行调整和修订

性能

您的问题正确地将此问题标识为用户与问题之间的 Many-To-Many 关系,其中每个用户可以回答许多问题,并且每个问题可能由许多用户回答。在关系数据库设计中,只有一种正确的方式来表示 many-to-many。这种方法是添加第三个 child table,有时称为 "bridge table",外键链接到两个 parent table 中的每一个。

在你画 parent tables 比 child tables 垂直向上的图表中,我个人看到这样的 many-to-many作为蝴蝶或鸟类图案的图表,其中 child 桥 table 是 body/thorax,两个 parent 是翅膀。

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