数据模型设计步骤:逻辑模型
引言
此文是用以快速回顾关系数据库主要设计步骤的几篇短文中的第二篇,描述的是数据库设计中的第二阶段——逻辑模型(logical model)设计的步骤,对应 (Connolly 和 Beg 2015) 第17章的内容。为方便读者查阅原书相关内容,我已在本文中给出了关键概念的英文名称。
值得一提的是,如果在概念模型设计阶段采用了视图集成的方式为系统设计了多个局部概念模型(local conceptual model),那么在逻辑模型设计阶段就需要分多次执行本文将介绍的步骤1-步骤5,然后再在步骤6中对结果进行合并。
步骤1:将概念模型中的实体类型、联系类型和属性转换成关系
概念模型主要通过实体类型(entity type)、联系类型(relationship type)及它们所含有的属性(attribute)来对数据进行描述;逻辑模型由概念模型衍生而来,但主要通过关系(relation)来对数据进行描述。因此,在概念模型基础上构建逻辑模型的第一步,就是将前者所含有的各类对象转换成关系。按照转换方法的不同,前面提到的概念模型的各类对象可以进一步细分为:
- 强实体类型;
- 弱实体类型;
- 一对多(1:*)二元联系类
- 一对一(1:1)二元联系类型;
- 一对一(1:1)递归联系类型;
- 超类/子类联系类型;
- 多对多(*:*)二元联系类型;
- 复杂联系类型;
- 多值属性。
读者可参阅 Connolly 和 Beg (2015) 在原书第17章介绍的相关内容进一步了解将上述各类对象转换成关系的具体方法。为了描述经上述转换过程得到的关系,我们可以创建一幅新的ER图(entity relationship diagram)1 并在其中记录各关系的以下要点2 :名称、所包含的简单属性(simple attribute)、主键(primary key)、可替换键(alternate key)、外键(foreign key)、派生属性(derived attribute)及其计算方法;另外,在记录外键时,应同时注明其参照了哪个关系的哪个属性(可以用线段将参与联系的关系连接起来)。
1 虽然原书建议使用数据库定义语言(DataBase Definition Language, DBDL)作为逻辑模型的描述方法,但ER图应该更加常用、直观,所以我认为用后者来描述逻辑模型可能更好一些。但值得注意的是,概念模型的ER图和逻辑模型的ER图有不同的记法,因此在使用时需要注意区分。
2 这里提到的大多数内容已在构建概念模型的时候确定,因此构建逻辑模型时可直接参考相关内容。但值得一提的是,弱实体的主键并未在构建概念模型时确定,而需要在此步骤中完成。
步骤2:使用规范化方法对关系进行验证
设计关系数据库逻辑模型的第二步是使用规范化(normalization)方法对关系进行验证和改进。值得一提的是,由于确定每个关系中各属性间的函数依赖(functional dependency)关系是实施规范化的基础、而函数依赖的确定又取决于设计者对属性含义的理解,因此在开展此步骤前设计者必须先确保自己对属性含义有着准确的理解;另外,尽管存在着更高等级的范式(normal form),但一般来说各关系只需满足第三范式(3NF)即可。在对关系进行规范化后,应该更新ER图和数据字典中的相应部分,使之能够准确反映规范化的结果。
如需进一步了解数据库基本范式的实现条件及方法,可以阅读另一篇相关文章。
步骤3:通过用户事务验证关系
设计关系数据库逻辑模型的第三步是检查逻辑模型是否支持用户需求规格说明书中描述的用户事务。我们可以利用与概念模型设计的第8个步骤类似的方法进行验证。如果发现逻辑模型无法支持某些事务,则说明其存在问题(这些问题很可能是在前两个步骤中创建关系的时候出现的),需要进行相应处理。
步骤4:检查完整性约束
设计关系数据库逻辑模型的第四步是检查模型是否反映了用户需求规格说明书中指定的数据完整性(data integrity)约束。值得一提的是,此步骤只关心数据模型中需要包含哪些约束,并不关心应该如何实现这些约束。常见的数据完整性可以分成以下几类:
- 定义域完整性(domain integrity);
- 实体完整性(entity integrity);
- 参照完整性(referential integrity);
- 用户定义完整性(user-defined integrity)。
实际上,定义域完整性和实体完整性分别已在概念模型设计的第4和第5步中确定。因此,此步骤应着重关注参照完整性和用户定义完整性。
在确定参照完整性时,需要考虑两个问题。第一个问题是,外键是否允许为空?一般而言,如果子关系对某联系的参与性(participation)是强制的(mandatory),那么与该联系对应的外键就不允许为空;如果 其参与性是可选的(optional),那么外键则可以为空。另外一个问题是,当出现可能破坏参照完整性的数据更新操作时应该采取何种措施保持参照完整性?可能破坏参照完整性的数据更新操作主要涉及以下几种情形:1. 在子关系中插入一个新元组;2. 修改子关系中某元组的外键值;3. 从父关系中删除被子关系参照的元组;4. 修改父关系中被子关系参照的元组的主键值。对于第1和第2种情形,我们需要确保子关系中新增或修改的元组的外键值要么为空(如果子关系在该联系中的参与性是可选的话)、要么必须存在于所参照的属性的值的集合中。对于第3和第4种情形,我们可以根据实际需求从以下几种措施中选择最合适的措施:NO ACTION——禁止进行删除或更新操作;CASCADE——删除子关系中所有相关的元组、或修改这些元组的外键值;SET NULL——将子关系 中所有相关元组的外键值设为空;SET DEFAULT——将子关系中所有相关元组的外键值设为默认值;NO CHECK——不进行任何处理。
用户定义完整性的制定主要基于业务规则和用户需求规格说明书中的内容,包括多重性(multiplicity)约束等,此处不赘述。
在制定数据完整性约束之后,需要将这些约束记录进ER图或数据字典中。
步骤5:与用户共同复核逻辑模型
设计关系数据库逻辑模型的第五步是与用户一起对模型进行复核。复核主要围绕ER图和数据字典进行。如果发现模型中存在任何问题,就必须进行相应的修改,而这可能需要重复前面的步骤。复核的过程可能需要重复多次,直至用户确认模型能够充分地满足需求。
步骤6:将多个局部模型合并成全局模型(可选步骤)
只有当数据库系统包含多个用户视图(user view)、且设计者采用了视图集成(view integration)的方式进行设计时,此步骤才是必须的。当系统比较复杂时,视图的合并需要采用比较系统的方法,原书(Connolly 和 Beg 2015)第17章对此进行了详细介绍,此处不再赘述。在完成合并后,我们还需再次通过用户事务来验证关系,并再次和用户共同复核合并后的模型;另外,设计者应该修改ER图和数据字典,使之能够反映合并的结果。
步骤7:检查模型的可扩展性
设计关系数据库逻辑模型的最后一步是判断在可预见的未来里系统功能需求是否会发生明显变化、以及模型是否能够通过扩展来适应这些变化。设计者在此步骤中可能需要对模型进行一定调整,使之在将来能够通过最小的改动来适应这些可能出现的新需求。在对模型进行改动后,需要及时更新ER图和数据字典以反映这些改动。
小结
本文简要描述了关系数据库逻辑模型设计的主要步骤。对于本文中提到、但未深入讲解的内容,感兴趣的读者可以从原书(Connolly 和 Beg 2015)相关章节中获取更多信息。