---
url: /doc/Databases/nf5w6gx1/index.md
---
> 著作权归 JavaGuide(javaguide.cn)所有 基于 MIT 协议 原文链接：https://javaguide.cn/database/basis.html

## Cue

* 数据库、数据库管理系统、数据库系统、数据库管理员
* 元组、码、候选码、主码、外码、主属性、非主属性
* ER 图
* 函数依赖（部分函数依赖、完全函数依赖、传递函数依赖） 数据库范式（非主属性于码的函数依赖关系）
* 主键与外键
* 存储过程
* drop、delete 与 truncate
* 数据库设计步骤

## Main

### 数据库相关概念

* **数据库（DB）**：信息的集合，由数据库管理系统管理。
* **数据库管理系统（DBMS）**：操纵和管理数据库的软件，用于建立、使用和维护数据库。
* **数据库系统（DBS）**：由软件、数据库和数据库管理员组成。
* **数据库管理员（DBA）**：全面管理和控制数据库系统。

### 数据库基本组成

* **元组**：关系数据库中表的每行记录。
* **码**：能唯一标识实体的属性。
* **候选码**：能唯一标识元组且其子集不能标识的属性组。
* **主码**：从候选码中选出的唯一标识元组的属性。
* **外码**：一个关系中的属性是另一个关系的主码。
* **主属性**：候选码中出现的属性。
* **非主属性**：不包含在候选码中的属性。

### ER 图

![](./01-数据库.assets/c745c87f6eda9a439e0eea52012c7f4a.png)

* **定义**：表示实体类型、属性和联系的图。
* **组成**：
  * **实体**：用矩形框表示，如学生、教师。
  * **属性**：用椭圆形表示，如姓名、年龄。
  * **联系**：用菱形表示，如学生与课程的多对多关系。

### 数据库范式

> * **函数依赖（functional dependency）**：若在一张表中，在属性（或属性组）X 的值确定的情况下，必定能确定属性 Y 的值，那么就可以说 Y 函数依赖于 X，写作 X → Y。
> * **部分函数依赖（partial functional dependency）**：如果 X→Y，并且存在 X 的一个真子集 X0，使得 X0→Y，则称 Y 对 X 部分函数依赖。比如学生基本信息表 R 中（学号，身份证号，姓名）当然学号属性取值是唯一的，在 R 关系中，（学号，身份证号）->（姓名），（学号）->（姓名），（身份证号）->（姓名）；所以姓名部分函数依赖于（学号，身份证号）；
> * **完全函数依赖(Full functional dependency)**：在一个关系中，若某个非主属性数据项依赖于全部关键字称之为完全函数依赖。比如学生基本信息表 R（学号，班级，姓名）假设不同的班级学号有相同的，班级内学号不能相同，在 R 关系中，（学号，班级）->（姓名），但是（学号）->(姓名)不成立，（班级）->(姓名)不成立，所以姓名完全函数依赖与（学号，班级）；
> * **传递函数依赖**：在关系模式 R(U)中，设 X，Y，Z 是 U 的不同的属性子集，如果 X 确定 Y、Y 确定 Z，且有 X 不包含 Y，Y 不确定 X，（X∪Y）∩Z=空集合，则称 Z 传递函数依赖(transitive functional dependency) 于 X。传递函数依赖会导致数据冗余和异常。传递函数依赖的 Y 和 Z 子集往往同属于某一个事物，因此可将其合并放到一个表中。比如在关系 R(学号 , 姓名, 系名，系主任)中，学号 → 系名，系名 → 系主任，所以存在非主属性系主任对于学号的传递函数依赖。

* **1NF**：属性不可再分，是关系型数据库的基本要求。
* **2NF**：在 1NF 基础上，消除非主属性对码的部分函数依赖。

> **示例**
>
> 假设有一个表 Orders，包含以下字段：
>
> OrderID（订单 ID）
> CustomerID（客户 ID）
> ProductID（产品 ID）
> ProductName（产品名称）
> CustomerName（客户名称）
> 在这个表中，主键是 OrderID、CustomerID 和 ProductID 的组合。
>
> 检查 2NF
> 满足 1NF：每个字段都是原子的，没有重复的组或子列表。
>
> 消除部分函数依赖：
>
> ProductName 只依赖于 ProductID，而 ProductID 是主键的一部分。
> CustomerName 只依赖于 CustomerID，而 CustomerID 是主键的一部分。
> 因为 ProductName 和 CustomerName 都部分依赖于主键的一部分，而不是整个主键，所以这个表不满足 2NF。
>
> 解决方案：
>
> 为了使表满足 2NF，可以将表分解为多个表，消除部分函数依赖：
>
> Orders 表：
>
> OrderID
> CustomerID
> ProductID
> Products 表：
>
> ProductID
> ProductName
> Customers 表：
>
> CustomerID
> CustomerName
> 通过这种方式，每个非主属性都完全函数依赖于其所在表的主键，从而满足 2NF。

![](./01-数据库.assets/bd1d31be3779342427fc9e462bf7f05c.png)

* **3NF**：在 2NF 基础上，消除非主属性对码的传递函数依赖。

### 主键与外键

* **主键**：唯一标识元组，不能重复，不允许为空。
* **外键**：用于建立表间联系，可以重复，可以为空。

> - 为什么不推荐使用外键和级联？
>
>   阿里巴巴开发手册：
>   【强制】不得使用外键与级联，一切外键概念必须在应用层解决。
>
>   说明: 以学生和成绩的关系为例，学生表中的 student\_id 是主键，那么成绩表中的 student\_id 则为外键。如果更新学生表中的 student\_id，同时触发成绩表中的 student\_id 更新，即为级联更新。外键与级联更新适用于单机低并发，不适合分布式、高并发集群；级联更新是强阻塞，存在数据库更新风暴的风险；外键影响数据库的插入速度
>
>   一是增加复杂性，如 DELETE、UPDATE 操作需考虑约束，且主从关系固定，需求变更时调整麻烦；
>
>   二是增加额外工作，数据库需维护外键，消耗资源，而应用层面维护可减轻数据库压力；
>
>   三是对分库分表不友好。但外键也有好处，如保证数据一致性和完整性，级联操作方便。
>
>   是否使用外键应根据系统情况综合考虑，不涉及分库分表且并发量不高可以考虑使用。

### 存储过程

* **定义**：SQL 语句和逻辑控制语句的集合。
* **优点**：方便复杂业务操作，执行效率高。
* **缺点**：难以调试和扩展，消耗数据库资源。

### drop、delete 与 truncate

* **drop**：删除表及其结构。
* **truncate**：清空表数据，不删除表结构。
* **delete**：删除表中特定数据。

> drop、delete 与 truncate 区别？
>
> * `drop`和`truncate`是 DDL 语言，而 `delete` 是 DML 语言。
> * 执行时间`drop` > `truncate` > `delete`，delete` 产生binlog日志便于回滚，`truncate` 不产生日志且重置自增和索引，`drop\` 释放表空间。
>
> DML 是用于数据库表记录操作（插入、更新、删除、查询）的语言，使用频繁；DDL 是用于数据库对象（如表）的创建、删除、修改的语言，多由 DBA 使用。执行速度一般为：
>
> `select` 有时被单独称为 DQL。

### 数据库设计步骤

1. **需求分析**：分析用户需求。
2. **概念结构设计**：采用 E-R 模型设计。
3. **逻辑结构设计**：将 E-R 图转换为表。
4. **物理结构设计**：选择存储结构和存取路径。
5. **数据库实施**：编程、测试和试运行。
6. **运行和维护**：日常维护和系统运行。

## Summary

本文介绍了数据库的基本概念、组成、设计方法和相关操作。通过理解数据库、数据库管理系统、数据库系统和数据库管理员的区别，以及元组、码、候选码等概念，可以更好地设计和管理数据库。ER 图、数据库范式、主键与外键的使用，以及存储过程和 SQL 操作的区别，都是数据库设计和开发中的重要知识点。掌握这些内容，能够帮助我们高效地进行数据库设计和优化。
