2

下面是一个类似的(和简化的)例子来设计问题,我面对:关系数据库设计(正火许多一对多映射)

假设你有学生,类和档次。学生可以有很多不同的课程。每个班级都有许多不同的学生。每个(学生,班级)对都有一个等级。

我应该布局数据库(MySQL数据库),如:

选项1)

students table - (student_id, student_name) 
classes table - (class_id, class_name) 
students_classes table - (student_class_id, student_id, class_id) 
grades table - (student_class_id, grade) 

选项2)

students table - (student_id, student_name) 
classes table - (class_id, class_name) 
grades table - (student_id, class_id, grade) 

还是应设计成别的东西吗?选项2现在看起来更简单了,但在将来,我可能需要与每个(student_id,class_id)对相关的其他统计信息(在这种情况下,选项1似乎更好一些?但选项1仍然感觉有点过于复杂)。

你有什么建议?谢谢。

+0

在你的榜样,是不是成绩的学生的属性? – JNK 2010-11-19 20:26:16

+0

假设它也可以是一个数字等级 – Peter1491 2010-11-19 20:27:40

+0

@JNK:是的,但它也是班级的一个属性 - 学生可能在数学中获得A,在英语中获得F. – 2010-11-19 20:35:45

回答

3

选项3)

students table - (student_id, student_name) 
classes table - (class_id, class_name) 
students_classes table - (student_class_id, student_id, class_id, grade) 

级是学生类的属性。

除非等级有可能成为一个完整的实体。在这种情况下:

选项4)

students table - (student_id, student_name) 
classes table - (class_id, class_name) 
students_classes table - (student_class_id, student_id, class_id) 
grades table - (grade_id, grade, student_class_id) 
+1

+1选项4是明智的,将涵盖3NF – gbn 2010-11-19 20:44:23

+3

-1。这两个选项都不正确。 'student_class'不需要'student_class_id',它是一个冗余列,带有一个额外的索引,并打开了表中的重复项。 PK是'(student_id,class_id)'。如果你删除它,你会得到选项2,但应该命名为'student_class'。 “成绩”是基于错误的,所以也是不正确的。如果Grade成为“完整的**实体**”,那将是另一回事,在这里它仅仅是一个1 :: 1的子表;可以将其标准化为'student_class'。 – PerformanceDBA 2010-11-28 04:50:45

+1

@gbn。 ???您使用的是3NF的定义? – PerformanceDBA 2010-11-28 04:51:15

0

我是第三范式的粉丝,你有独立的学生,班级和成绩表,并将其与诸如ClassStudent和GradeClass之类的多对多表联系起来。

但这取决于你将来如何维护它。最终归结为未来的扩展和可维护性。这就是为什么我更喜欢3NF。

编辑

AXN的answer比我好得多。

+0

+1记住,许多桌子在变大时都很慢。其他我完全同意。 – 2010-11-19 20:28:15

+0

但在这个例子中,我需要一个ClassStudentGrade表。 (因为学生可以有很多等级......但是每个班级只有1个等级,所以每个学生班级都有1个等级) – Peter1491 2010-11-19 20:28:48

+0

3NF独立于OP – gbn 2010-11-19 20:36:12

-1

这一切都取决于,真的。选项1可能是执行此应用程序最可靠的方式;选项2可能会让你更快地进行这个迭代。选项2 - > 1的变化是否会在未来变得痛苦?你有多确定你需要额外的灵活性?

我会建议只是选择1.查询不会更复杂,如果你使用ORM(如ActiveRecord for Rails,其中很多),那么差异几乎为零。

+2

问题是关于数据库设计和规范化,而不是关于应用程序可以或不可以轻松做什么。我认为你的意思是“无”。 – PerformanceDBA 2010-11-28 05:06:38

3

我会亲自去选择2。成绩的复合主键没有任何问题,它会捕获数据模型中所需的信息。

在选项1中,students_classes除了拥有代理键​​之外没有其他用途。

编辑,看到其他的答案后:

  • 2NF:等级(非重点)完全取决于学生/班(重点)
  • 3NF:不适用。您对非关键的依赖没有非关键
  • BCNF:不适用,你有一个候选键只有
+2

选项2 ** IS ** 3NF。您已正确识别组合键,但您尚未注册“分级”是对其的1 :: 1纯依赖关系。 – PerformanceDBA 2010-11-28 04:42:36

+1

-1。选项2 **是** 3NF。您已正确识别组合键,但您尚未注册该分数是对它的纯1 :: 1依赖性。 – PerformanceDBA 2010-11-28 05:08:40

1

选项2是正确的,但它应该被称为student_class,反映其n :: n功能,或作为注册的实体。而(student_id, class_id)就是PK。

等级(如您所示)是对该复合键(不在其他元素上)的1 :: 1依赖关系,因此它是student_class的属性。

也因此student_class是3NF。

如果人们没有盲目地坚持使用Id所有移动的iot列,就像您使用选项1一样,他们将能够更好地理解数据,从而更好地规范化。那(Id选项1中的iot列作为起点)干扰了你的直觉,即(student_id, class_id)是标识符;没有额外的Id iot列及其额外索引是必要的。然后当你开始评估grade时,它对该PK的依赖是显而易见的。

Id IOT列损坏数据库的关系的能力。如果您在层次结构中说了三个表格,并且您需要从顶部和底部表格中获取一些列,则您不得不通过中间表格。如果你有关系标识符,而不是白痴列,你可以从底部表格到顶部表格读取中间表格。

在“规范化”数据库中存在如此多的连接只有一半。完整的事实是,由于数据库没有正确规范化,是的,你被迫进入比必要更多的连接。在一个真正的Normalized数据库中,使用相同的表格,代码需要的连接少得多。

下面是最近分配的>Data Model for a College<,简化版本。

>IDEF1X Notation<对于那些需要解释符号的人。

  • 注意只需要一个代理键。

    • 这是因为在替代方案中,(名字+姓+ Initials_BirthDate + BithDate)将是人PK,这将在5子/孙子表,这是81个字节进行如FK,那就是不明智的。
  • 看看你是否可以认识到标识符(实线)是通过儿童和孙子的;他们有和传达的意义

  • 当我们有一个完美的PersonId,这是外键和已经唯一的时候,为TeacherId,StudentId,StaffId添加代理键会很愚蠢。 (列被命名为这样的,以确定自己的角色。)

  • 所有业务规则是在执行DDL:FK约束;检查约束;规则。

    • 房间有一个4列复合键;提供有3列复合键;这两者一起消除了双重预订。

    • 提供PK和学生PK一起组成登记PK(与此问题相同; PK由不同的列构成,就是这些)。

+0

“注意只需要一个代理键。” - 为什么*需要*?区分具有相同名字,姓氏,出生地点和出生日期的两个人吗? – 2010-12-22 10:56:59

+1

@Tomislav。在引用的文本中编辑我的帖子。我们可以假设AK的唯一性可以通过其他方式得到保证,例如。这是一个例子,一个真正的数据库会有一个UpdatedDateTime列等。相比之下,'Room' PK(4列,简称)作为非识别FK在'Offering'中携带。 – PerformanceDBA 2010-12-22 11:57:25