数据模型设计步骤:物理模型
引言
此文是用以快速回顾关系数据库主要设计步骤的几篇短文中的第三篇,描述的是数据库设计中的第三阶段——物理模型(physical model)设计的步骤,对应 (Connolly 和 Beg 2015) 第18和19章的内容。为方便读者查阅原书相关内容,我已在本文中给出了关键概念的英文名称。
步骤1:根据目标数据库管理系统特性对逻辑模型进行转换
设计关系数据库物理模型的第一步是将逻辑模型中定义的关系(relation)转换成可以由目标数据库管理系统(database management system, DBMS)实现的形式。此步骤又可以进一步细分为以下三个小步骤。
步骤1.1:定义基础关系
使用目标数据库的数据定义语言(data definition language, DDL)1定义基础关系。在定义时应着重关注以下要点:
1 虽然原书建议使用扩展的数据库定义语言(DataBase Definition Language, DBDL)来描述基础关系,但我认为这种方式存在两个缺点:首先,DBDL可能与目标数据库的DDL存在不兼容的地方,这将导致设计与实现之间存在不一致;其次,为了实现物理模型,DBDL最终还是需要被转换成DDL。考虑到这些因素,我认为直接使用目标数据库的DDL来描述基础关系可能会更好。
- 关系的名称;
- 基础属性(base attribute)的名称、定义域(内容包括数据类型、长度、合法值、可否为空等)、默认值;
- 主键(primary key)、可替换键(alternate key)、外键(foreign key),需要特别一提的是,在定义外键时不仅要描述属性的参照关系,还应该描述当参照完整性遭到破坏时,应该采取何种策略(例如NO ACTION、CASCADE等,详见另一篇文章的相关介绍)应对。
步骤1.2:选择派生数据的表示方法
针对每个派生属性(derived attribute),考虑是否需要在数据库中存储其数据值。一般而言,考虑主要基于以下几个因素:
- 存储开销;
- 计算开销,以及目标DBMS是否支持相关计算;
- 维护数据一致性的难度。
如果经过考虑,决定要在数据库中存储某派生属性的话,应该在对应关系的DDL中增加该属性的定义,并通过注释说明其计算方法。
步骤1.3:设计用户定义完整性约束
在步骤1.1中,我们通过设置定义域、主键和外键保证了定义域完整性(domain integrity)、实体完整性(entity integrity)和参照完整性(referential integrity)。而在此步骤1.3中,我们需要进一步完善数据完整性,并设置逻辑模型中描述的用户定义完整性(user-defined integrity);实现该类完整性的方法主要包括:
- 在DBMS中设置
CHECK
约束; - 在DBMS中设置触发器(trigger);
- 编写特定的应用程序代码。
步骤2:选择文件组织方法和索引
设计关系数据库物理模型的第二步是选择合适的文件组织方法和索引,以便满足系统性能需求。此步骤又可以进一步细分为以下四个小步骤。
步骤2.1:分析事务
在此步骤中,可以借助事务/关系交叉引用矩阵(transaction/relation cross-reference matrix)、事务使用图(transaction usage map)、事务分析表(transaction analysis form)等手段了解系统中存在那些重要的事务、以及这些事务的相关信息,例如:所涉及的关系、属性(在分析时应特别关注属性的用法,例如是否出现在WHERE或JOIN等子句中)、访问类型(查询、插入或更新)及数据量,运行频率、峰值及时间段等等。
步骤2.2:选择文件组织方法
在目标DBMS支持的前提下,为每个关系选择最佳的文件组织方式;如果目标DBMS不支持用户选择文件组织方式,则跳过此步骤。
原书附录F.7介绍了选择文件组织方式的一般性原则,此处不再赘述。
步骤2.3:选择索引
在决定是否为某些属性创建索引时,可以参考以下一般指南:
- 不要为仅含有少量数据的关系创建索引,因为直接从内存中进行搜索可能更快;
- 一般来说,如果尚未为主键构建索引,则应该补建索引(一般来说,DBMS会自动为主键构建索引,但也可能有例外);
- 如果一个外键经常被访问,则应该为其构建索引(有的DBMS会自动为外键构建索引);
- 如果一个可替换键经常被使用,那么应该为其构建索引;
- 为经常出现在WHERE、JOIN、ORDER BY、GROUP BY子句中的属性建立索引;
- 为经常出现在聚集函数(aggregate function)中的属性建立索引;
- 为能产生仅用索引规划(index-only plan)的属性建立索引;
- 避免为经常需要插入、删除、更新的关系或属性建立索引;
- 如果查询可能检索出占关系中相当比例(比如>25%)的元组,就应该避免为关系中的属性添加索引,因为直接在内存中检索可能更快;
- 避免为长字符串类型的属性构建索引。
步骤2.4:估计硬盘空间需求
估计硬盘空间需求,以决定系统硬件配置。
原书附录J介绍了如何对数据库中关系的大小进行评估的方法,此处不再赘述。
步骤3:设计用户视图
设计关系数据库物理模型的第三步是使用目标数据库DDL定义在需求分析阶段产生的用户视图(user view)。
步骤4:设计安全机制
设计关系数据库物理模型的第四步是根据需求分析结果为数据库设置安全机制,以实现系统安全(system security)和数据安全(data security)。其中,系统安全内容涵盖数据库系统层面上的访问和使用,如用户名和密码等;数据安全内容则涵盖用户对数据库对象(如关系、视图等)的访问、使用以及可进行的操作。
原书第20章对安全进行了更全面的讨论,此处不再赘述。
步骤5:考虑引入可控冗余
设计关系数据库物理模型的第五步是结合系统性能,考虑是否需要对关系进行去规范化(denormalization)。通常来说,如果系统性能无法满足要求,并且查询所涉及的关系具有较低的更新频率但同时具有较高的查询频率,去规范化就很可能是一种有效的策略。具体而言,可以考虑以下逆规范化操作:
- 合并一对一(1:1)联系;
- 在一对多(1:*)联系中引入重复的非键属性(non-key attribute)以减少连接操作;
- 在一对多(1:*)联系中引入重复的外键属性以减少连接操作;
- 在多对多(*:*)联系中引入重复属性以减少连接操作;
- 引入重复组(repeating group);
- 创建抽取表(extract table);
- 对关系进行分区(partitioning)。
每种操作的适用条件及所需注意的问题请参见原书第19章,此处不再赘述。
步骤6:对系统性能进行监测并调优
设计关系数据库物理模型的第六步是监控系统运作情况,并保证系统性能满足需求。系统性能主要通过事务吞吐率、响应时间和磁盘占用空间三个指标来评价;当发现这些指标达不到要求时,需要寻找性能瓶颈,并进行有针对性的优化。
小结
本文简要描述了关系数据库逻辑模型设计的主要步骤。对于本文中提到、但未深入讲解的内容,感兴趣的读者可以从原书(Connolly 和 Beg 2015)相关章节中获取更多信息。