改进在线考试的数据库设计

时间:2015-04-29 14:07:05

标签: mysql database database-design

我正在开发一个多选在线测试项目,我设计了数据库来存储结果,但寻找更优化的方法。

要求:

  1. 每个问题都有四个选项。
  2. 只能选择一个选项,需要将其存储在数据库中。
  3. 我的设计:

    表:

    学生
      stud_id,名称,电子邮件

    测试
      test_id,testname,duration

    问题
      que_id,question,opt1,opt2,opt3,opt4,answer,test_id

    答案
      stud_id,que_id,回答

    通过这种方式可以存储答案但是它会增加记录的数量,因为学生新记录解决的每个问题都将添加到答案表中。

    e.g。 一个测试包含100个问题,1000个学生参加该测试,每个学生每个问题将有100个记录,1000个学生将有100个记录。

    在记录数量较少的情况下,有没有更好的方法呢?

2 个答案:

答案 0 :(得分:16)

初步回复

了解数据

你做得很好。就数据而言,设计是正确的,但不完整。有两个错误:

  1. opt1…opt4是一个重复组,打破2NF。它必须放在一个单独的表中。

    • 此外,似乎没有选项名称或描述符,这很奇怪(您在页面上绘制什么,在每个单选按钮旁边?)

    • 如果您添加了第五个选项,那么现在可以提供;如果您对少于四个选项有疑问,现在可以满足。

    • 相反,您有一组固定的列,如果将来有任何此类更改,您必须更改数据库和现有代码。并且代码将是可怕的(额外处理而不是直接SELECT)

  2. 您的answers表没有完整性。就目前而言,答案可以根据学生未被问到的问题或者学生没有参加的考试进行记录。防止这种类型的错误是关系数据库中的普通费用,并且在记录文件系统中是不可能的。

    • 在IT的这些黑暗时期,这是一个普遍的趋势。人们关注数据;他们想象电子表格中的,它们直接用于实现包含那些的对象。

    • ,而不是理解数据及其含义。

    • answers(stud_id, que_id, answer)没有任何意义,没有完整性,除非断言了student_test的上下文。

  3. 第三项不是错误,因为您没有将其作为要求。但是,在我看来,一个问题可以在多个测试中使用。你设置它的方式,这些问题将被复制(数据库的重点是规范化它,这样就没有重复了。)

    • 当然,结果是一个关联表,test_question.
  4. 问题

      

    通过这种方式可以存储答案但是会增加记录的数量,因为学生新记录解决的每个问题都将添加到答案表中。

    是。这对数据库来说是正常的。

      

    有更好的方法可以在记录数量较少的情况下这样做。

    对于记录文件系统,是的。对于数据库,没有。由于您已将问题标记为数据库设计,我将假设这就是您想要的。

    数据库是事实的集合,而不是具有相关字段的记录。事实是关于现实世界的,仅限于数据库和应用程序的范围。

    确定我们需要的离散事实很重要,因为从属事实依赖于高阶事实。那就是数据库设计。而且,随着我们的进步,我们将数据规范化,作为同一个练习的一部分。规范化的目的是消除重复,否则您有更新异常。当我们进步时,我们再次确定关系密钥,作为同一个练习的一部分。关系密钥提供关系数据库的逻辑结构,即。逻辑完整性。

      

    e.g。一个测试包含100个问题,1000个学生参加该测试,每个学生每个问题将有100个记录,1000个学生将有100个记录。

    是。但这在ISAM记录处理术语中表达。在数据库术语中,您无法绕过数据库存储的事实:

    • 关于100个问题的事实

    • 关于1,000名学生的事实

    • 大约1,000名学生的事实乘以他们做出的100项选择

    你需要了解两件事:大量不连续的事实;和复合键的使用。两者都对关系数据库至关重要。如果其中任何一个丢失,或者你不情愿地实现它们,你就不会拥有关系数据库的完整性,功能或速度,你将拥有1970年以前的ISAM记录文件系统。

    此外,SQL平台,以及某种程度上的NONsql平台,如myNONsql,都经过大量优化,可以处理数据集(不是逐个记录);繁重的I / O和缓存;如果实现高并发性所需的结构,您将获得更高的性能。

    实施

    就实现而言,特别是因为您关注性能,所以存在错误。重述是,在理解并正确建模数据之前,不应尝试实施。

    全面的问题是,你已经添加了一个代理(没有"代理键"这只是一个代理,一个物理记录ID)。在模拟练习中还有很长的路要走;它还没有取得足够的进展;该模型不稳定,可以添加替代品。

    • 代理人总是一个额外的列加上基础索引。显然,这会消耗资源,并且在插入和删除方面会产生成本。

    • 代理不提供行唯一性,这在关系数据库中是必需的。

    • 关系模型要求密钥由数据组成。关系键提供行唯一性。

    • 代理人不是由数据组成的。因此它不是关系密钥,并且它不提供任何一种质量。

    • 如果使用代理,它不会替换密钥,另外 密钥。这就是为什么我们在数据建模之后而不是之前评估代理的需求。这是一个实现问题,而不是建模问题。

    解决方案

    让我提供提案,而不是来回走动,你可以讨论它。

    • Student Test Data Model(仅限第1页,适用于进展后的人)。

    • 如果您不习惯乐谱,请注意每个小刻度,刻痕和标记,实线与虚线,方形与圆角,意味着非常具体。请参阅IDEF1X Notation

    • 对于testquestion.我已经离开了id列,但请注意,使用简短有意义的代码会更好。

    • student_id有效,因为nameemail都太大而无法迁移到子表。

    • 请仔细检查动词短语,它们包含一组谓词。其余的Predicates可以直接从模型中确定。如果不清楚,请询问。

    • 看看你是否可以确定这是一个事实的集合,每个事实都是离散的,因为其他事实依赖于它;它不是具有相关字段的记录集合。

      
        

    您的answers表没有完整性。就目前而言,答案可以根据学生未被问到的问题或者学生没有参加的考试进行记录。防止这种类型的错误是关系数据库中的普通费用,并且在记录文件系统中是不可能的。

      
    • 现在已经阻止了。现在名为answers的{​​{1}}表具有一定的完整性。 student_response,已在student中注册了student_test,student_responses被限制为student_test.

    请评论/讨论。

    对评论的回应

      

    我将添加额外的表主题(subject_id,subject_name)并在问题表中添加该subject_id,因为FK可以吗?

    是的,无论如何。但这会产生后果。一些建议,以确保我们全面正确地做到这一点:

    1. 如上所述,除非绝对必要,否则请勿使用代理人(记录ID)。对于用户和开发人员而言,短代码对标识符要好得多。

      • 如果您想了解与ID列相关的问题的更多信息,请阅读this Answer
    2. 主题很重要。在这种情况下,(a)存在question,(b)存在test。它们确实作为独立项目存在(DM的第1页),但现在它们从属于subject.这种添加大大提高了数据的完整性。

    3. 学生注册的事实和学生参加考试的事实,都是离散的,单独的事实。

    4. 感激地,消除了两个代理question_idtest_id.codes,例如CHAR(2)更容易,也更有意义。

    5. 注意表名的改进,提高了清晰度。

    6. 我更新了Student Test Data Model(仅适用于进展后的那些人)。

    7. 然而,这暴露了一些东西(这就是为什么我们建模数据,纸张便宜,许多草稿是正常的)。如果我们评估Predicates(在数据模型中很容易看到,详见IDEF1X Notation文档):

         each subject_test was taken by 0-to-n student_tests
         each student_test is [a taking of] 1 subject_test
         each student took 0-to-n student_tests
         each student_test is taken by 1 student
      

      那些谓词不准确。 student可以test代表subject.任意subject给定新的students表,我认为我们希望subjects,注册student_test因此,subjects被约束为student注册的student_test

      • 如果您想了解谓词的重要关系概念,以及如何使用它来理解和验证模型,请访问this Answer,向下滚动,直至找到谓词部分,仔细阅读。
    8. 我更新了Student Test Data Model(第3页)。现在我们有了更多的完整性,因此subjects被约束为student注册 each student registered for 0-to-n student_subjects each student_subject is a registration of 1 student each subject attracted 0-to-n student_subjects each student_subject is an attraction of 1 subject each subject_test was taken by 0-to-n student_tests each student_test is [a taking of] 1 subject_test each student_subject took 0-to-n student_tests each student_test is taken by 1 student_subjects 。相关的谓词是:

      ID
    9. 现在数据模型似乎已完成。

      • Context是数据库中的所有内容。

      • 数据层次结构在密钥的复合中清晰可见。

      • 请注意,子表中的关系密钥为层次结构中的每个更高级别(父级,祖父级)提供了与父表的关系完整性。

      • 如果不明显,请注意关系联接的力量。对于在每个文件中都有student_response个字段的记录归档系统,您无法做到的事情。例如:

        • subject直接加入subject_code上的student_response,而无需浏览中间的两个级别

        • student直接加入student_id上的{{1}},而无需浏览中间的两个级别

答案 1 :(得分:5)

不,没有更好的设计,因为设计与表中的记录数无关。无论你是处理十个学生还是一万个学生,你都会选择相同的设计。

你的桌子设计看起来不错。不要担心记录的数量。 dbms用于处理大型表。而100k记录仍然是一个小型数据库。如果存在数十亿的答案,我甚至不会改变这种设计。