在重构我的项目数据库之前,我想先理清楚数据库的范式问题。
为什么要规范化
单个关系的大型数据库可能会导致数据重复。这种数据重复可能会导致:
使关系非常大。
维护和更新数据并不容易,因为它涉及搜索相关的许多记录。
磁盘空间和资源的浪费和利用率低下。
错误和不一致的可能性增加。
因此,为了处理这些问题,我们应该分析冗余数据的关系并将其分解为更小、更简单、结构良好且满足所需属性的关系。规范化是将关系分解为具有较少属性的关系的过程。
范式的作用主要是为了消除这些异常现象。
什么是范式
数据库规范化,又称范式、标准化,是数据库设计的一系列原理和技术,以减少数据库中数据冗余,增进数据的一致性。
范式是评价数据库模式规范化程度从低到高主要有:1NF、2NF、3Nf、BCNF、4NF、5NF。
现在数据库设计最多满足 3NF,普遍认为范式过高,虽然具有对数据关系更好的约束性,但也导致数据关系表数量增加,从而导致数据库 IO 更易繁忙。过高的范式,其实相当于将原本由数据库实现的关系约束,转移到了更高一级的数据库管理程序中实现。
1NF
表的列的具有原子性,不可再分解, 第一范式(1NF)解决了列重复的问题。
考察下面的关系表:
student_id | name | dept | dept_phone | course | course | grade |
1 | 张三 | CS | 67123467 | 英语 | 英语 | 80 |
2 | 李四 | SE | 67123468 | 软件工程 | 软件工程 | 75 |
2 | 李四 | SE | 67123468 | 英语 | 英语 | 70 |
出现了两个含义相同的列,不满足1NF。删除重复的列,得到下面的关系表:
student_id | name | dept | dept_phone | course | grade |
1 | 张三 | CS | 67123467 | 英语 | 80 |
2 | 李四 | SE | 67123468 | 软件工程 | 75 |
2 | 李四 | SE | 67123468 | 英语 | 70 |
满足了1NF。
不满足1NF的关系表是比较反直觉的,往往我们一开始设计的数据库就已经满足了1NF。
2NF
第二范式(2NF)解决了非主键列对主键的部分函数依赖问题。
考虑下面的关系表,其已经满足了1NF:
student_id(PK) | name | dept | dept_phone | course(PK) | grade |
1 | 张三 | CS | 67123467 | 英语 | 80 |
2 | 李四 | SE | 67123468 | 软件工程 | 75 |
2 | 李四 | SE | 67123468 | 英语 | 70 |
其主键似乎可以设置为(student_id,course)。但是如果这样的话,存在下面的依赖关系:
dept_phone→dept→student_id
这意味着dept_phone与dept列仅依赖student_id,但不依赖另一个主键course。所以这个关系表不满足2NF,需要进一步分解。
分解后可以如下:
student_id(PK) | name | dept | dept_phone |
1 | 张三 | CS | 67123467 |
2 | 李四 | SE | 67123468 |
2 | 李四 | SE | 67123468 |
student_id(PK) | course(PK) | grade |
1 | 英语 | 80 |
2 | 软件工程 | 75 |
2 | 英语 | 70 |
3NF
第三范式(3NF)解决了传递函数依赖问题。
考虑下面的关系表:
student_id(PK) | name | dept | dept_phone |
1 | 张三 | CS | 67123467 |
2 | 李四 | SE | 67123468 |
2 | 李四 | SE | 67123468 |
如果dept与dept_phone是一一对应的关系,那么在关系表中同时记录两个值就是重复的。此时存在依赖关系dept_phone→dept→student_id,存在非主键的传递依赖。因此这个关系表不满足3NF,需要进一步分解。
分解后可以如下:
student_id(PK) | name | dept |
1 | 张三 | CS |
2 | 李四 | SE |
2 | 李四 | SE |
dept(PK) | dept_phone |
CS | 67123467 |
SE | 67123468 |
SE | 67123468 |
BCNF
属于修正的第三范式,是防止主键的某一列会依赖于主键的其他列。 如果3NF 消除了主属性对码的部分函数依赖和传递函数依赖,就被称为 BCNF。
4NF
非主属性不应该有多值。如果有多值就违反了第四范式。4NF 是限制关系模式的属性间不允许有非平凡且非函数依赖的多值依赖。
5NF
第五范式消除了 4NF 中的连接依赖,表必须可以分解为较小的表,除非那些表在逻辑上拥有与原始表相同的主键。
对于BCNF以上的范式,我并不打算深入研究。不仅因为其过于复杂,也因为上面提到的,它们可能导致性能问题,所以并不实用。