SQL语言艺术 —— Stéphane Faroult 读书笔记
规范化使混沌变得有序。
遵循基于严格逻辑规则的数据库三范式,能够帮助数据库管理员维护、扩展、更新数据库,同时,规范化的数据库设计,也能保证开发人员能够编写优雅的数据操作代码。
1. 确保原子性
所谓原子性,即是确保表中的每一个字段不再可分。但判断数据是否具有原子性需要对具体数据具体分析,例如,按国家分析数据时,一个国家就是具有原子性的单位,按月份分析数据时,一个月就是具有原子性的单位,分析身体状况时,人的各项指标就具有原子性。所以,该问题其实并不存在一般性,我们应该对于具体数据,具体分析,面向数据编程(Data Oriented Programming)。
当我们设计表时,应该把原子属性定义为表中的字段,以保证高效的搜索能力和数据的正确性。
- 高效的搜索能力,以车辆的“安全系统”为例,可能包含防锁死刹车系统(ABS)、安全气囊、集中式锁控等,如果仅使用
safety_equipment
属性来描述这些设备,搜索配备了 ABS 的车辆时,则需要对每行数据进行扫描,效率很低; - 数据的正确性,同样以“安全系统”为例,若希望搜索配备了 ABS 的车辆,却输入了 ASB,这样结果一定是错误的,但如果将每一个安全系统作为字段,数据库就会帮我检查出这些错误了。
确定了所有的原子数据项之后,下一步便是确定主键(PK)。一般而言,应当使用具有实际意义主键,主键应该能刻画数据的特色,而不是简单的递增整数。
一旦所有属性都具有原子性,且确定了键,即满足了数据库第一范式。
2. 检查对键的完全依赖性
假设我们有如下“二手车”表:
品牌 | 型号 | 版本 | 款式 | 出产年份 | 总里程数 | 座位数 | 载货量 | … |
其中品牌、型号、款式、出产年份和总里程数合在一起为联合主键。但事实上,一旦确定了品牌、型号、版本和款式,座位数和载货量也就确定了,不需要考虑出产年份和总里程数,也即是说座位数和载货量仅部分依赖主键。
这会造成两个问题:
- 数据的冗余,假设有许多品牌、型号、版本和款式都相同的车待售,那么这些属性会被重复保存,保存的次数与同类型车辆的数量相同,这造成了存储空间的浪费,修改他们也往往费时费力;
- 查询性能降低,如果需要查询汽车的所有款式,那么就必须使用
select distinct
操作,大幅降低性能。
因此,需要建立以下表:
- A (品牌、型号、版本、款式、座位数、载货量),以品牌、型号、版本、款式作为联合主键;
- B (品牌、型号、版本、款式、出产年份、里程数、…),以品牌、型号、版本、款式、出产年份、里程数作为联合主键。
去除了只依赖部分键的属性后,即满足了数据库第二范式。
3 检查属性的独立性
第三范式要求数据集中的每个字段仅依赖主键,且非主键字段之间不能存在依赖关系。
若不满足第三范式,问题与第二范式中基本上相同。
以下表为例:
学号 | 姓名 | 学院名称 | 学院电话
此处只要知道了学院名称,学院电话就被确定了,因此,学院电话字段将出现大量冗余,因此应对学生和学院分别建表。
学生:学号 | 姓名 | 学院名称
学院:学院名称 | 学院电话
以学院名称为外键,可以关联学生表和学院表。
总之,规范化使数据的组织有序,合理规范化的模型能够灵活的应对业务需求的变化,保证数据库的可维护和可扩展性。