【问题标题】:Database design for many-to-many relations with restrictions具有限制的多对多关系的数据库设计
【发布时间】:2015-07-25 11:09:19
【问题描述】:

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

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

还有其他方法可以提高性能吗?

【问题讨论】:

    标签: sql database-design sqlperformance


    【解决方案1】:

    您可能想要这样的设置。

    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 约束来确保唯一性 - 使用代理键通常是出于易用性的目的,但这绝不是必要的。

    【讨论】:

      【解决方案2】:

      图表

      下面是我自己的表格设计图,与 jpw 的correct Answer 非常相似。我编造了一些列名,以便更多地了解表格的性质。我使用了Postgres 数据类型。

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

      不切实际

      此图符合问题中的问题描述。然而,这种设计是不可行的。这种情况是针对向用户提出的一组问题,只有一次调查或测验。在学校、民意调查或焦点小组等现实生活中,我希望我们会向用户发送多个问卷。但我会忽略这一点,直接按措辞解决问题。

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

      性能

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

      在您将父表垂直绘制在页面上高于子表的图表中,我个人将这种多对多图表视为蝴蝶或鸟模式,其中子桥表是身体/胸部,两个父母是翅膀。

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

      【讨论】:

        猜你喜欢
        • 2011-05-03
        • 1970-01-01
        • 2011-04-13
        • 2012-09-30
        • 2011-05-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多