企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持知识库和私有化部署方案 广告
[TOC] ## 完整性约束 数据库的**完整性约束(Integrity Constraints)是用来确保数据库中数据的正确性、一致性**和**有效性**的规则 <br/> 完整性约束的作用就是: * **保证数据质量**:防止非法或不一致的数据被存储。 * **简化应用开发**:将业务规则定义在数据库层面,而不是在每个应用代码中重复编写,从而减少了开发者的工作量。 * **提高数据可靠性**:即使在多个应用程序同时访问数据库时,也能确保数据的一致性。 <br/> ### 几种主要完整性约束类型 关系型数据库系统(如 MySQL, PostgreSQL, SQL Server 等)通常支持以下几种核心的完整性约束: #### 1\. 实体完整性(Entity Integrity) 实体完整性确保表中每一行记录都有一个**唯一** 的标识。它通过**主键约束(Primary Key Constraint)** 来实现。 * **规则**: * 主键列的值必须是唯一的,表中不能有重复的主键值。 * 主键列的值不能为 `NULL`(空值)。 * **作用**:唯一标识表中的每一条记录,是表的核心。例如,在学生表中,`学号` 可以设为主键,确保每个学生的记录都是独一无二的。 #### 2\. 参照完整性(Referential Integrity) 参照完整性确保表与表之间引用的数据关系是正确的。它通过\*\*外键约束(Foreign Key Constraint)\*\*来实现。 * **规则**: * 外键列的值必须要么为空值 `NULL`,要么是它所引用的**主表**中的主键值。 * **作用**:建立表与表之间的关联,并保持这种关联的有效性。例如,在一个 `订单表` 中,`客户ID` 可以作为外键,它引用 `客户表` 中的 `客户ID` 主键。这保证了每一个订单都必然对应一个真实存在的客户,防止出现“无主”订单。 #### 3\. 域完整性(Domain Integrity) 域完整性确保列中的数据满足特定的数据类型、格式和有效值范围。 * **规则**: * **非空约束(NOT NULL)**:确保列的值不能是空值 `NULL`。 * **唯一约束(UNIQUE)**:确保列中的所有值都是唯一的,但与主键不同,它允许 `NULL` 值(通常可以有多个 `NULL`)。 * **默认值约束(DEFAULT)**:为列指定一个默认值。当插入新记录时,如果没有为该列提供值,则会自动使用默认值。 * **检查约束(CHECK)**:为列中的值设置一个逻辑表达式,确保插入的值必须满足该表达式。例如,可以将 `年龄` 列设置为 `CHECK(年龄 >= 18)`。 * **作用**:对单个列的数据进行严格控制,确保数据的有效性。 #### 4\. 用户自定义完整性(User-defined Integrity) 除了以上三种,数据库还允许用户根据具体的业务需求定义更复杂的完整性规则。这些规则通常通过\*\*存储过程(Stored Procedures)**和**触发器(Triggers)\*\*来实现。 * **作用**:处理那些无法通过简单的约束来表达的复杂业务逻辑,比如“一个学生的选课总学分不能超过25分”。 ## 关系数据库设计基本理论 ### 函数依赖 #### 函数依赖(Functional Dependency) - 定义:在关系模式 R 中,若属性集 X 的值能唯一确定属性集 Y 的值,记作 **X → Y**。 - 示例: - 在学生表(学号, 姓名, 系名), - 学号 → 姓名、系名 (学号能唯一确定学生的姓名和系名)。 ##### 完全函数依赖 Y 完全依赖于 X,不能去掉 X 的任意一个属性。 例子: 在一个包含课程号和学生号的复合主键表中,学生的成绩完全依赖于(课程号, 学生号)这个组合,缺一不可 ##### 传递函数依赖 例子: 在一个包含**课程号和学生号的复合主键表中**,`学号 → 系主任`是一个函数依赖,但它不是完全依赖,因为实际是`学号->系号->系主任` > 这种部分依赖是导致**第二范式**(2NF)违规的主要原因 ##### 部分函数依赖 Y 依赖于 X 的一部分。 - 示例: - (学号, 课程号) → 成绩 (完全依赖) - (学号, 课程号) → 姓名 (部分依赖,因为姓名只依赖学号) #### 平凡函数依赖(Trivial Functional Dependency) - 定义:如果 Y 是 X 的子集,则依赖 **X → Y** 称为平凡函数依赖。 - 示例: 假设我们有一个关系 `R` (学号, 姓名, 班级)。 - {学号, 姓名} → {姓名} - {学号} → {学号} - {学号, 班级} → {学号, 班级} 这些都是平凡函数依赖 #### 非平凡函数依赖(Non-trivial Functional Dependency) - 定义:如果 Y 不是 X 的子集,但依赖 **X → Y** 仍然成立,那么称为 **非平凡函数依赖**。 - 示例: - `{学号}` → `{姓名}` - `{学号}` → `{班级}` - `{班级}` → `{系主任}` 这些依赖是非平凡的 ## 多值依赖 例如 |Student| Hobby |Course| |---|---|---| |Tom| Reading| Math| |Tom| Reading| Physics| 这就是多值依赖。它不是因为某个值决定另一个值,而是因为一个属性的值集与另一个属性的值集是**相互独立且必须同时存在**的,如 Hobby 和 Course 多值依赖会导致**数据冗余**和**更新异常** ### Armstrong 六条公理 * **自反律(Axiom of Reflexivity)** * **规则:** 如果 B 是 A 的一个子集,那么 A→B 成立。 * **例子:** 如果我们有一个属性集 {姓名,班级},那么 {姓名,班级}→{姓名} 永远成立。这很好理解,知道了 {姓名,班级} 的值,当然也就能确定 {姓名} 的值。 * **增广律(Axiom of Augmentation)** * **规则:** 如果 A→B 成立,那么对于任何属性集 C,都有 AC→BC 成立。 * **例子:** 如果我们知道 “学号” 函数决定 “姓名”,即 学号→姓名。那么,如果我们增加一个属性 “班级”,`{学号, 班级}` 依然能决定 `{姓名, 班级}`。 * **传递律(Axiom of Transitivity)** * **规则:** 如果 A→B 成立,并且 B→C 成立,那么 A→C 也成立。 * **例子:** 如果我们知道 “学号” 决定 “班级”,即 学号→班级,并且 “班级” 决定 “系主任”,即 班级→系主任。那么,我们可以推导出 “学号” 决定 “系主任”,即 学号→系主任 * **合并规则(Union Rule)**: * 规则:如果 X → Y 且 X → Z,则 X → YZ。 * 解释:如果 X 同时决定 Y 和 Z,则 X 决定 Y 和 Z 的并集。 * 示例:A → B 且 A → C,则 A → BC。 * **分解规则(Decomposition Rule)**: * 规则:如果 X → YZ,则 X → Y 且 X → Z。 * 解释:从一个复合依赖可以分解为单个依赖。 * 示例:A → BC,则 A → B 且 A → C。 * **伪传递规则(Pseudotransitivity Rule)**: * 规则:如果 X → Y 且 WY → Z,则 XW → Z。 * 解释:传递律的变体,允许在 Y 的右边添加 W。 * 示例:A → B 且 BC → D,则 AC → D(W = C)。 ## 关系代数操作实例 名词说明 * **超键**:在关系模式中,能唯一标识一条记录的 **属性集** * **候选键**:能唯一标识的属性组合(最小化), 最小的超键,不能再去掉任何属性,否则就不能唯一标识 * **主码**:候选键里挑出来的“代表”。 * **主属性**:属于候选键的字段。 * **非主属性**:不在候选键里的字段。 * **外键**:引用别的表主键的字段。 ### 1. 第一范式(1NF) - 定义:关系模式 R 的 **每一个分量必须是不可再分的数据项**。 - 通俗理解:字段值必须是原子的,不可再拆分。 - 示例:不能在一个字段中同时存储多个电话号码。 ### 2. 第二范式(2NF) - 定义:在满足 1NF 的基础上,**所有非主属性必须完全依赖于主码**。 - 通俗理解:不能出现 **部分依赖**(即非主属性只依赖于主码的一部分)。 - 示例:若主键为 (学号, 课程号),成绩依赖于二者,而不能只依赖其中之一。 表:学生选课表 | 学号 | 课程号 | 姓名 | 年级 | 成绩 | |------|--------|------|------|------| | 1001 | C01 | 张三 | 大一 | 95 | | 1001 | C02 | 张三 | 大一 | 88 | | 1002 | C01 | 李四 | 大二 | 90 | | 1002 | C03 | 李四 | 大二 | 85 | **分析** - 主键: (学号, 课程号) —— 因为一门课程对应多个学生,一个学生也能选多门课。 - 非主属性:姓名、年级、成绩。 - 依赖情况: - **成绩** 完全依赖 (学号, 课程号) ✅ - **姓名、年级** 只依赖于学号 ❌(部分依赖) ### 3. 第三范式(3NF) - 定义:在满足 2NF 的基础上,**所有非主属性都必须直接依赖于主码,而不能传递依赖**。 - 通俗理解:消除 **传递依赖**。 - 示例:学号 → 系名,系名 → 系主任,那么学号 → 系主任就是传递依赖,应消除。 表:学生信息表 | 学号 | 姓名 | 系名 | 系主任 | |------|------|--------|--------| | 1001 | 张三 | 计算机 | 王老师 | | 1002 | 李四 | 数学 | 李老师 | | 1003 | 王五 | 计算机 | 王老师 | | 1004 | 赵六 | 物理 | 陈老师 | **问题分析** - 主键:学号 - 非主属性:姓名、系名、系主任 - 依赖关系: - 姓名、系名 直接依赖学号 ✅ - **系主任 依赖 系名,而系名又依赖学号 → 出现传递依赖 ❌** ### 4. BC 范式(BCNF) -BCNF 解决的问题是:在一个表中,**如果存在非主键属性能够决定主键的一部分,或者能决定另一个非主键属性,那么这个表就不符合 BCNF。** - BCNF 的核心思想是:**任何非平凡的函数依赖,其决定因素(左边)必须是超键** 示例: 在表`学号,课程,指导老师` 中 * **`{学号, 课程}` → `指导老师`**:要唯一确定一位指导老师,必须知道学生和课程。这是这个表唯一的**候选键**,所以它也是**主键**。 * **`指导老师` → `课程`**:根据业务规则,一位指导老师只教一门课。所以,只要知道指导老师,就能确定唯一的课 BCNF 的要求是:**对于每一个非平凡函数依赖 `X → Y`,`X` 必须是超键。** * 第一个依赖 `{学号, 课程}` → `指导老师`:左边是 `{学号, 课程}`,这是主键,也是超键,所以这个依赖**符合** BCNF 的要求。 * 第二个依赖 `指导老师` → `课程`:左边是 `指导老师`,它**不是**超键(因为它不能唯一标识一条记录,比如王教授教数据库,但不同的学生选这门课)。因此,这个依赖**不符合** BCNF 的要求 ### 5. 第四范式 主要解决的是 **多值依赖(Multivalued Dependency, MVD)** 问题 例子: 学号 课程 社团 101 数据库 篮球社 101 数据库 辩论社 “课程”和“社团”这两个属性是**相互独立**的,它们都依赖于“学号”这个主键,但彼此之间没有直接关系。这导致了大量的数据冗余,违反第四范式 ## 分布式是数据库 - 传统集中式数据库的两阶段提交协议**加锁阶段**和**解锁阶段**也称为**扩展阶段**和**收缩阶段**, - 分布式数据库两阶段提交协议中的两个阶段是指**表决阶段**、**执行阶段** ## 数据库并发操作的影响 * **脏读**:一个事务读到了另一个事务还未提交的数据。 * **不可重复读**:同一事务内两次读取同一数据,结果却不一致。 * **幻读**:同一事务内两次查询,结果的行数不一致(因为插入或删除)。 * **丢失修改**:两个事务更新同一数据,后提交的覆盖了前提交的修改。