现代数据库还需要设计范式吗?

什么是范式

在设计关系数据库时,为了减少数据冗余和提高数据一致性而遵循的一系列规则和标准。

范式的基本原则

  1. 保证列的原子性.
  2. 通过对表进行人工的笛卡尔积分解来得到最少的数据耦合.

概览

优点

  1. 数据极度的不冗余, 存储占用较低
  2. 指导了如何切分数据以及构造

缺点

  1. 数据非常难构造, 需要用到大量的join.
  2. 性能差
  3. 不符合直觉

现代计算机系统如何进行数据库设计

在现代计算机系统中,数据库范式设计仍然是一个重要的概念,但它的应用需要根据具体的业务需求和性能要求进行权衡。

范式设计的必要性

数据库范式设计的主要目标是减少数据冗余和提高数据一致性。通过将数据拆解为原子表,范式设计可以有效地防止数据的重复和更新异常。例如,通过第三范式(3NF),我们可以确保一个表中的非主键字段不依赖于另一非主键字段,进而避免冗余数据的存储。

然而,过度的范式化带来的问题也非常明显。在性能敏感的场景下,过度的范式化会导致以下问题:

  • 复杂的查询:多表连接(JOIN)操作会变得复杂且耗时,影响查询性能。
  • 维护困难:表结构过于复杂,维护和理解成本增加。

减少数据耦合的两种方式

  1. 设计范式

    • 优点:减少数据冗余,提高数据一致性,数据更新时不会产生异常。
    • 缺点:表结构复杂,查询性能可能较差,尤其是在需要频繁进行多表连接的情况下。
  2. 领域驱动设计 (DDD)

    • 优点:通过逻辑上划分数据的作用域,定义领域(Bounded Context),在领域内允许一定的反范式设计,从而简化表结构和查询操作。
    • 缺点:需要更复杂的领域建模和设计,领域之间的数据协调可能需要额外的机制。

数据冗余的可接受性

在现代计算机系统中,数据冗余在某些场景下是可以接受的,尤其是在性能敏感的应用中。具体原因如下:

  • 性能优先:在实时性要求高的系统中,例如金融交易系统、电商系统等,查询性能至关重要。适度的数据冗余可以减少复杂的表连接,提升查询速度。
  • 存储成本降低:存储成本的下降使得适度的数据冗余在经济上变得可行。以往为了节省存储空间而极力避免的数据冗余,现在可以通过增加存储空间来解决。
  • 业务需求:在实际业务中,有时需要快速响应查询请求,甚至在业务逻辑上存在特殊需求,这时适度的数据冗余可以简化查询逻辑,提高系统的响应速度。

考虑因素

  • 业务需求:根据具体的业务需求来决定数据的范式化程度。在一些关键业务场景下,允许适度的数据冗余以简化查询和提升性能。
  • 性能要求:对于性能敏感的系统,应尽量减少复杂的多表连接,适度增加数据冗余以提高查询速度。
  • 维护成本:过度的范式化可能增加系统的维护成本,因此需要在范式设计和实际维护之间找到平衡点。
  • 领域驱动设计:引入领域驱动设计思想,合理划分领域,减少领域之间的耦合,允许领域内适度的反范式设计,以提高系统的整体性能和可扩展性。

小结

在现代计算机系统中,虽然范式设计依然重要,但在实际应用中,应根据具体的业务需求和性能要求进行权衡。适度的数据冗余在很多场景下是可以接受的,尤其是在性能敏感的系统中。

数据库的六种范式

第一范式 (1NF)

定义

第一范式要求数据库表中的每一列都是原子的,即每个字段只包含单一值,不允许重复的组或多值属性。

示例

假设我们有一个表 students​,记录学生的信息:

不符合第一范式的表结构

students
-------------------------------
| student_id | name | subjects |
-------------------------------
| 1          | John | Math, Science |
| 2          | Jane | English |
| 3          | Bob  | Math, History |
-------------------------------

在这个表中,subjects​ 列包含了多个值,这不符合第一范式。

符合第一范式的表结构

students
--------------------
| student_id | name |
--------------------
| 1          | John |
| 2          | Jane |
| 3          | Bob  |
--------------------

student_subjects
------------------------
| student_id | subject  |
------------------------
| 1          | Math     |
| 1          | Science  |
| 2          | English  |
| 3          | Math     |
| 3          | History  |
------------------------

在这个表结构中,students​ 表和 student_subjects​ 表都只包含单一值的字段,符合第一范式。

第二范式 (2NF)

定义

第二范式要求在满足第一范式的基础上,表中的每个非主键字段都完全依赖于主键,而不是部分依赖于主键。即如果一个表的主键是由多个字段组成的组合键,那么表中的非主键字段必须依赖于整个组合键。

示例

假设我们有一个表 course_enrollments​,记录学生选课的信息:

不符合第二范式的表结构

course_enrollments
------------------------------------------------------
| student_id | course_id | course_name     | grade   |
------------------------------------------------------
| 1          | 101       | Math            | A       |
| 1          | 102       | Science         | B       |
| 2          | 101       | Math            | A       |
| 3          | 103       | History         | B       |
------------------------------------------------------

在这个表结构中,course_name​ 依赖于 course_id​,而不是整个组合键 (student_id​, course_id​)。

符合第二范式的表结构

course_enrollments
---------------------------
| student_id | course_id | grade |
---------------------------
| 1          | 101       | A     |
| 1          | 102       | B     |
| 2          | 101       | A     |
| 3          | 103       | B     |
---------------------------

courses
----------------------
| course_id | course_name |
----------------------
| 101       | Math        |
| 102       | Science     |
| 103       | History     |
----------------------

在这个表结构中,course_name​ 被移到 courses​ 表中,course_enrollments​ 表中的非主键字段都完全依赖于主键。

第三范式 (3NF)

定义

第三范式要求在满足第二范式的基础上,表中的非主键字段之间没有传递依赖关系。即一个非主键字段不能依赖于另一个非主键字段。

示例

假设我们有一个表 employees​,记录员工的信息:

不符合第三范式的表结构

employees
----------------------------------------------
| employee_id | name  | department_id | department_name |
----------------------------------------------
| 1           | John  | 10            | HR              |
| 2           | Jane  | 20            | IT              |
| 3           | Bob   | 10            | HR              |
----------------------------------------------

在这个表结构中,department_name​ 依赖于 department_id​,而 department_id​ 是一个非主键字段。

符合第三范式的表结构

employees
-----------------------
| employee_id | name  | department_id |
-----------------------
| 1           | John  | 10            |
| 2           | Jane  | 20            |
| 3           | Bob   | 10            |
-----------------------

departments
-------------------------
| department_id | department_name |
-------------------------
| 10            | HR              |
| 20            | IT              |
-------------------------

在这个表结构中,department_name​ 被移到 departments​ 表中,employees​ 表中的非主键字段之间没有传递依赖关系。

BC范式 (BCNF)

定义

BC范式要求在满足第三范式的基础上,表中的每个决定因素都是候选键。即如果一个表中存在非主键字段决定其他字段的情况,那么这个非主键字段必须是候选键。

示例

假设我们有一个表 project_assignments​,记录员工分配到项目的信息:

不符合BC范式的表结构

project_assignments
---------------------------------------
| employee_id | project_id | manager_id |
---------------------------------------
| 1           | 101        | 201        |
| 2           | 101        | 201        |
| 3           | 102        | 202        |
---------------------------------------

在这个表结构中,manager_id​ 依赖于 project_id​,而 project_id​ 不是候选键。

符合BC范式的表结构

project_assignments
---------------------------
| employee_id | project_id |
---------------------------
| 1           | 101        |
| 2           | 101        |
| 3           | 102        |
---------------------------

projects
------------------
| project_id | manager_id |
------------------
| 101        | 201        |
| 102        | 202        |
------------------

在这个表结构中,manager_id​ 被移到 projects​ 表中,project_id​ 是候选键。

第四范式 (4NF)

定义

第四范式要求在满足BC范式的基础上,表中不存在多值依赖。即一个表中的字段不能同时依赖于两个独立的多值属性。

示例

假设我们有一个表 students_courses​,记录学生的选课和活动信息:

不符合第四范式的表结构

students_courses
------------------------------------------
| student_id | course_id | activity_id |
------------------------------------------
| 1          | 101       | 501         |
| 1          | 102       | 502         |
| 2          | 101       | 503         |
------------------------------------------

在这个表结构中,course_id​ 和 activity_id​ 是独立的多值属性。

符合第四范式的表结构

students_courses
---------------------------
| student_id | course_id |
---------------------------
| 1          | 101       |
| 1          | 102       |
| 2          | 101       |
---------------------------

students_activities
---------------------------
| student_id | activity_id |
---------------------------
| 1          | 501         |
| 1          | 502         |
| 2          | 503         |
---------------------------

在这个表结构中,students_courses​ 和 students_activities​ 分开存储,避免了多值依赖。

第五范式 (5NF)

定义

第五范式要求在满足第四范式的基础上,表中的数据不能通过更小的表来无损分解。即确保表中的数据不能通过分解成更小的表来表示,而不丢失信息。

示例

假设我们有一个表 students_courses_teachers​,记录学生选课和授课教师的信息:

不符合第五范式的表结构

students_courses_teachers
-------------------------------------
| student_id | course_id | teacher_id |
-------------------------------------
| 1          | 101       | 301        |
| 1          | 102       | 302        |
| 2          | 101       | 301        |
-------------------------------------

在这个表结构中,student_id​ 和 course_id​ 以及 course_id​ 和 teacher_id​ 之间存在多值依赖。

符合第五范式的表结构

students_courses
---------------------------
| student_id | course_id |
---------------------------
| 1          | 101       |
| 1          | 102       |
| 2          | 101       |
---------------------------

courses_teachers
---------------------------
| course_id | teacher_id |
---------------------------
| 101       | 301        |
| 102       | 302        |
---------------------------

在这个表结构中,students_courses​ 和 courses_teachers​ 表分开存储,确保表中的数据不能通过分解成更小的表来表示,而不丢失信息。

posted @ 2024-06-04 00:20  pDJJq  阅读(8)  评论(0编辑  收藏  举报