--- title: "06-数据库" created: 2026-08-29 tags: - 基础与理论 - 信息基础大赛 --- # 第 85~108 题:数据库 > 📚 本文是 [[00-信息基础大赛|信息基础大赛]](10.29 备赛)的第 6 篇,题目以截图为主、文字为点拨。 ## 概念 数据库管理员(DBA) ![[image142.png]] ![[image143.png]] ![[image144.png]] 数据库(DataBase =>DB) 在数据库管理系统的集中控制下,按一定组织方式存储起来的、相互关联的数据的集合。 数据库管理系统(DataBase Management System => DBMS) 组织和存储数据、维护和获取数据的一个软件:Oracle、MySQL、Access、SQL Server ![[image145.png]] ![[image146.png]] ![[image147.png]] ![[image148.png]] ![[image149.png]] ![[image150.png]] ![[image151.png]] ![[image152.png]] ![[image153.png]] ![[image154.png]] 数据库应用系统(DataBase Application System=>DBAS) 基于数据库所建立的应用。以数据库为基础的财务管理系统、人事管理系统、图书管理系统等等。无论是面向内部业务和管理的管理信息系统,还是面向外部,提供信息服务的开放式信息系统,从实现技术角度而言,都是以数据库为基础和核心的计算机应用系统。 数据库系统(DataBase System=>DBS) 五大部分: 计算机的软硬件、数据库、数据库管理系统、数据库应用系统、相关人员 ![[image155.png]] ![[image156.png]] ![[image157.png]] 数据库系统的发展可以大致分为以下几个阶段: 文件系统阶段: 在计算机科学的早期,数据管理主要依赖于文件系统。每个应用程序都会独立管理自己的数据文件,这导致了数据冗余、数据一致性问题以及缺乏数据安全性。这个阶段通常被称为"文件系统阶段",它没有提供任何数据集成和数据共享的机制。 ![[image158.png]] 层次数据库和网络数据库阶段: 20世纪60年代和70年代,出现了层次数据库和网络数据库模型。这些数据库系统试图解决文件系统的问题,引入了更结构化的数据管理方法。层次数据库模型使用树状结构来组织数据,而网络数据库模型引入了更灵活的数据组织方式。然而,这些模型仍然有一些限制,如复杂的查询和数据依赖关系管理。 关系数据库阶段: 1970年代,关系数据库管理系统(RDBMS)的概念由Edgar F. Codd首次提出,这标志着数据库系统的重大发展。关系数据库采用了表格化的数据结构,使用SQL(Structured Query Language)进行数据查询和操作。这种模型提供了更简单的数据访问方式,支持复杂的查询和数据完整性。RDBMS如Oracle、MySQL、和Microsoft SQL Server等成为了主流。 NoSQL数据库阶段: 随着互联网应用的兴起,出现了对传统RDBMS的挑战。NoSQL数据库系统在2000年代开始兴起,它们采用不同的数据模型,如文档型、列族型、图形型等,以满足大规模、高性能、分布式和非结构化数据的需求。NoSQL数据库系统如MongoDB、Cassandra、和Redis等逐渐流行起来。 新SQL和分布式数据库阶段: 随着数据规模的快速增长,分布式数据库系统变得越来越重要。一些新SQL数据库系统试图在关系数据库和NoSQL之间找到平衡,提供分布式数据存储和处理能力,同时保留传统RDBMS的一些特性。分布式数据库系统如Hadoop、HBase、和Spanner等也成为了关键的技术,支持大规模数据处理和存储。 云数据库和Serverless数据库阶段: 云计算的兴起改变了数据库系统的部署方式。云数据库服务提供商如Amazon Web Services(AWS)、Microsoft Azure和Google Cloud提供了托管的数据库解决方案,简化了数据库的管理和扩展。Serverless数据库服务允许开发者无需关心底层基础设施,只需专注于应用程序逻辑,这是数据库系统的新趋势。 ![[image159.png]] ![[image160.png]] ![[image161.png]] 关系: DBS范畴最大 ![[image162.png]] 三级模式: 外模式、模式和内模式 数据独立性是指应用程序与数据之间相互独立、互不影响。数据独立性包括物理独立性和逻辑独立性。物理独立性是指数据的物理结构发生改变时,数据的逻辑结构不必改变,从而应用程序不必改变;逻辑独立性是指当数据全局逻辑结构改变时,应用程序不必改变。 模式:(逻辑模式/概念模式) 全体数据的逻辑结构和特征的描述 所有用户的公共视图 一个数据库只有一个模式 ![[image163.png]] 外模式:(子模式/用户模式) 局部数据的逻辑结构和特征的描述 数据库用户(应用程序员、最终用户)的数据视图 介于模式和应用之间 模式与外模式:一对多 外模式与应用:一对多 每个用户只能访问对应的外模式中的数据 具有安全性 ![[image164.png]] 内模式:(存储模式) 数据物理结构和存储方式的描述 数据在数据内部的表示方式 一个数据库只有一个内模式 ![[image165.png]] DBMS在三级模式之间提供了二级映射功能 保证了数据库系统中的数据能够具有较高的逻辑独立性与物理独立性 ![[image166.png]] 二级映射: 外模式/模式映射: 外模式/模式映像保证了当模式改变时,外模式不用变 (逻辑独立性) 外模式/模式映象:定义外模式与模式之间的对应关系。 每个外模式都对应一个外模式/模式映像,在外模式中规定了从模式中如何分离出 外模式/模式映像的作用: 保证了数据的逻辑独立性。当模式改变时,数据库管理员修改有关的外模式/模式映像,使外模式保持不变;而应用程序是根据数据的外模式编写的,从而应用程序不必修改,保证了数据与应用程序的逻辑独立性,简称为数据的逻辑独立性。 模式/内模式映射: 模式/内模式映像保证了当内模式改变时,模式不用变 (物理独立性) 模式/内模式映像: 定义了数据全局逻辑结构与存储结构之间的对应关系(例如说明逻辑记录和字段在内部是如何表示的)。 数据库中模式/内模式映像是唯一的,定义在模式当中,保证了数据的物理独立性。 1)当数据的存储结构改变时(如本来我们用堆存储,改成了B+树),数据库管理员修改模式/内模式映像,使模式保持不变。 2)应用程序不受影响,保证了数据与程序的物理独立性,简称为数据的物理独立性。 ![[image167.png]] ![[image168.png]] 其他概念 ![[image169.png]] 与具体语言连接 ![[image170.png]] ![[image171.png]] ![[image172.png]] ## 数据库设计 ![[image173.png]] 数据库设计方法: 三范式、新奥尔良法、E-R模型设计方法等 数据库设计过程: 需求分析、概念设计、逻辑设计、物理设计、实施、运行与维护 ![[image174.png]] ![[image175.png]] 需求分析: 在此阶段,数据库项目的初衷和目标明确,与利益相关者(包括用户、管理层等)合作,以理解他们的需求和期望。 收集和分析数据需求,确定数据模型、数据量、性能要求、数据安全和隐私等方面需求 编写需求规格文档,其中包括用例、数据流图、实体-关系图等,以确保对数据库的要求清晰可行。 ![[image176.png]] DFD 是数据流图(Data Flow Diagram)的缩写,是一种流程建模工具,用于可视化和分析系统、应用程序或流程中的数据流动和处理。 DFD可以用来帮助分析和理解用户的数据需求。 通过绘制DFD,分析人员可以捕获用户与系统之间的数据流,识别系统的外部实体(数据源和数据目标)以及在系统内部的数据处理过程。 DFD有助于明确数据流和数据处理的要求,从而为后续的设计和实施提供指导。 概念设计: 在概念设计阶段,设计人员使用需求分析的结果来创建数据库的高级概念模型。 通常使用实体-关系图或其他概念建模工具来表示数据实体、关系、属性和约束。 目标是以高层次的方式定义数据结构,而不关心底层的数据库技术。 ![[image177.png]] 逻辑设计: 逻辑设计将概念模型转化为更详细和具体的数据库模型,通常使用关系模型。 定义数据库中的表格、字段、键(主键、外键)和数据完整性约束。 此阶段还包括查询的设计,以满足用户的数据检索需求。 ![[image178.png]] 物理设计: 物理设计是将逻辑数据库模型映射到具体数据库管理系统(DBMS)上的过程。 包括确定数据存储结构、索引、分区策略、缓存设置和性能调整等。 目标是优化数据库的性能、可伸缩性和安全性。 实施: 在实施阶段,数据库被创建和填充数据。 这包括选择合适的DBMS,创建表格、索引和视图,以及导入或手动输入数据。 应用程序也被开发或更新,以与数据库进行交互。 运行与维护: 数据库系统一旦投入运行,需要持续维护。 运行过程中的任务包括监控性能、备份和恢复、权限管理、数据清理等。 数据库的性能和安全性也需要不断进行调整和升级。 ### 概念模型到关系模型的转换(E-R图转向关系模型) ![[image179.png]] ![[image180.png]] ![[image181.png]] ![[image182.png]] ![[image183.png]] 简单点其实就是 看有几个实体集 和 几个多对多关系 最后得到的关系模式数量就是两者和 ![[image184.png]] ![[image185.png]] ![[image186.png]] ![[image187.png]] ![[image188.png]] ![[image189.png]] ![[image190.png]] ![[image191.png]] ## 数据库模型 数据库模型是一种抽象的结构,用于定义数据库中的数据如何组织、存储和管理。这些模型描述了数据的逻辑结构,包括数据的组织方式、关系、属性和约束。数据库模型通常定义了数据之间的关系,数据的操作方式,以及如何查询和访问数据。 文档型数据库模型: 用于存储和检索文档类型的数据,如JSON、XML和BSON。 数据以文档的形式组织,每个文档可以包含复杂的嵌套结构。 适用于半结构化数据,如Web内容、日志和配置文件。 代表性数据库系统:MongoDB、Couchbase。 键值型数据库模型: 用于简单的键值对存储,适用于高性能、低复杂性的数据存储需求。 数据存储为键值对,每个键关联一个唯一的值。 适用于缓存、会话管理和快速存储检索。 代表性数据库系统:Redis、DynamoDB。 列族数据库模型: 适用于需要存储和查询大规模数据集合的应用,如分布式文件系统和时间序列数据。 数据以列族(column family)的形式组织,每个列族包含多个列。 代表性数据库系统:Apache Cassandra、HBase。 层次模型(Hierarchical Model): 层次模型是早期的数据库模型之一,数据以层次结构的方式组织,其中一个记录可以包含多个子记录。这种模型通过树状结构来表示数据,其中顶层记录称为根,而底层记录称为叶子。虽然层次模型在某些情况下很有用,但它有一些限制,例如难以表示多对多关系。 网状模型(Network Model): 网状模型是一种较早期的数据库模型,用于描述数据实体之间复杂的关系。它允许实体之间的多对多关系,并通过使用记录之间的指针来表示这些关系。网状模型更灵活,但也更复杂,难以查询。 关系模型(Relational Model): 关系模型是一种数据库模型,数据以表格的形式组织,使用行和列来表示实体和属性。 关系模型使用结构化查询语言(SQL)进行查询和操作数据。 这是最常见和广泛使用的数据库模型,包括许多主流的关系数据库管理系统(RDBMS)。 关系数据库模型: 数据以表格(关系)的形式组织,使用SQL进行查询和管理。 表格由行和列组成,每个表格代表一个实体,行包含实例数据,列包含属性。 数据存储在关系数据库管理系统(RDBMS)中,支持事务处理和数据完整性。 代表性数据库系统:MySQL、Oracle、SQL Server。 平面关系模型(Flat Relational Model): 平面关系模型是关系型数据库模型的一种,其中数据以平面表格的形式组织,每个表格包含行和列。是关系数据库系统(如SQL数据库)的核心模型,其中数据存储在表格中,使用SQL查询进行访问和管理。 嵌套关系模型(Nested Relational Model): 嵌套关系模型是一种扩展的关系数据库模型,它允许表格中的数据列包含其他表格,从而支持更复杂的数据结构。适用于需要存储和查询嵌套或多层次数据的应用程序 分布式关系模型(Distributed Relational Model): 分布式关系模型是关系数据库模型的扩展,用于描述分布式数据库系统中的数据分布和交互。该模型涉及到在多个地理位置上分布的数据库服务器之间的数据复制、同步和查询操作。 图数据库模型: 用于存储和查询图形结构,非常适用于表示和处理复杂关系数据。 数据以节点和边的形式组织,支持高度连接的数据模型。 代表性数据库系统:Neo4j、ArangoDB。 复合对象模型(Complex Object Model): 复合对象模型是一种数据库模型,允许数据字段包含多个数据项或复杂的数据结构,如数组、集合或自定义对象。 这种模型适用于需要存储复杂数据类型的应用程序,如图形、多媒体和对象数据库系统。 对象关系模型(Object-Relational Model): 对象关系模型是关系数据库模型和面向对象数据库模型的结合,支持在关系数据库中存储和操作复杂的对象和类。 这个模型允许将对象、继承、多态性和其他面向对象的概念引入关系数据库系统,以处理更复杂的数据结构。 ![[image192.png]] ![[image193.png]] ![[image194.png]] ![[image195.png]] ![[image196.png]] ![[image197.png]] ![[image198.png]] ![[image199.png]] ## 关系代数 ![[image200.png]] ![[image201.png]] 关系操作: | 查询操作 | 更新操作 | |---|---| | 选择(Select) | 插入(Insert) | | 投影(Project) | 删除(Delete) | | 连接(Join) | 修改(Update) | | 除(Divide) | | | 并(Union)/交(Intersection)/差(Difference) | | | 广义笛卡尔积(Extended Cartesian Product) | | 关系运算 传统的集合运算(并、交、差、笛卡尔积) 专门的关系运算(投影、选择、联接、除) 基本运算(并、差、笛卡尔积、投影、选择)五种 辅助运算符 算术运算符:+、-、×、÷。 比较运算符:>、≥、<、≤、=、≠。 逻辑运算符:¬(逻辑非)、∧(逻辑与)、∨(逻辑或)。 包含运算符:∈(属于) ![[image202.png]] ![[image203.png]] ![[image204.png]] ![[image205.png]] ![[image206.png]] ![[image207.png]] ## 基本操作 ![[image208.png]] ![[image209.png]] ![[image210.png]] ## 视图 ![[image211.png]] ![[image212.png]] ![[image213.png]] ![[image214.png]] ![[image215.png]] ## 索引 ![[image216.png]] ![[image217.png]] ![[image218.png]] ![[image219.png]] ## trigger(触发器) 触发器(Trigger)是一种与数据库表相关联的特殊类型的存储过程,它在数据库发生特定事件(例如,插入、更新或删除操作)时自动执行。触发器通常用于实施数据完整性、业务规则、审计跟踪和其他数据库操作方面的自动化逻辑。触发器可以用于执行诸如检查约束、更新相关表、记录审计信息等任务。 触发器具有以下几个关键特点: 事件驱动性:触发器与数据库中的特定事件相关联。这些事件可以是INSERT、UPDATE或DELETE等数据操作。 自动执行:一旦触发事件发生,触发器会自动执行,而不需要手动触发。 与表相关:每个触发器都与特定表相关联,它在该表上监视特定事件。 包含逻辑:触发器包含一个或多个SQL语句,它们定义了触发事件发生时要执行的操作。 用途:触发器可用于实施数据完整性、执行业务规则、审计数据变更、自动计算派生数据等任务。 触发时机:触发器可以分为“BEFORE”触发器和“AFTER”触发器。BEFORE触发器在事件之前执行,通常用于对数据进行验证或修改。AFTER触发器在事件之后执行,通常用于记录审计信息或执行与事件相关的其他操作。 ![[image220.png]] 当插入新记录到员工表之前,触发器会检查工资是否低于30000,并在不满足条件时引发异常。 ## 事务 ![[image221.png]] ![[image222.png]] ### 事务调度 一组事务的基本步的一种执行顺序称作对这组事务的一个调度 (在隔离性里面提到过——就是如果多事务一起进行的话,具体步骤该是什么样的:如果先做完一个再做另一个,就会导致效率低的问题;如果两个同时做,效率就能加快,但同时也会产生很多问题,这就需要隔离级别去解决。但无论是一个一个执行还是并发式的一起执行,只要有步骤,就称其为事务的调度) 比如这里 1~6步执行事务1 7~12步执行事务2 这就是一个事务调度 因为是一个一个完成 所以称其为串行调度 ![[image223.png]] 当然就有并行调度(并发调度): 多个事务在宏观上来看是并行执行的 但其微观上的基本操作是交叉执行的 ![[image224.png]] ![[image225.png]] 显然 并发调度并不唯一 只要是交错进行的 就可以称其为并发调度 ![[image226.png]] 那么像这种判断是何种调度的题就没问题了 https://www.youtube.com/watch?v=X92w24yuUJY 接着往后走 只要是交错进行就叫并行调度 那这就会出现一些问题 如果同时访问的是一组数据 事务2的插入改变了事务1要用的数据的内容 那么这样一来 事务1的结果可能就会出错 所以 对于并发调度还要考虑一个正确性的问题 并发调度的正确性:当且仅当这个并发调度下所得到的新数据库结果与分别串行地运行这些事务所得的新数据库完全一致 则说明调度的正确的(只要最后结果对就对) 两个问题 怎么判断一个并发调度对不对?——【由结果反推就来不及了 错都错了】 怎么得到一个正确的并发调度? 对于问题1: 提出一个可串行性的概念: 如果不管数据库初始状态如何 一个调度对数据库状态的影响都和某个串行调度相同 则我们说这个调度的可串行化的(具有可串行性) 假定ABC初始都是100 ![[image227.png]] ![[image228.png]] A=90 B=90 C=120 A=90 B=110 C=120 两次结果并不一样 所以其为不可串行化调度 当然可以修改成可串行化调度 ![[image229.png]] A=90 B=90 C=120 可串行化调度一定是正确的并行调度 但正确的并行调度不一定是可串行化调度 (并行调度的正确性只管内容上的结果正确性 而可串行化是指形式上结果正确性) (如果把B=B-20 改成 B=B-0 那么上面那个不可串行化调度就与串行调度的结果一样了 但只是结果正确 本质还是不可串行调度) 为了更好研究调度 可串行性 有着这么一种模型——表示事务调度的模型 ![[image230.png]] (只要考虑读写就够了 其他操作不论怎么样 只要没执行写 数据库中内容就不会变) 但可串行化仍然是不太好判断的 那么就进一步严格些——冲突可串行性 ![[image231.png]] 同一事务不能换读写 即便对于不同元素 不同事务对同一元素的写或一读一写不能交换(涉及到同一元素的写就不行) 知道了哪些可以交换哪些不可以交换 那么就能把一个并行调度通过不断的交换 变成一个串行调度 ![[image232.png]] 不同事务对不同元素的读写 可以交换 不同事务的读 可以交换 不同事务对不同元素的写 可以交换 这个并发调度可以通过交换得到一个串行调度 就说明 它为冲突可串行化调度 (冲突可串行性是要比可串行性更严格的概念 又是充分不必要关系) ![[image233.png]] 这样就解决了第一个问题 怎么判断一个并发调度是正确的? ![[image234.png]] 从并发调度的正确性和可串行性角度去判断的话 只有知道结果才知道 那就来不及了 所以不能从这得到答案 但是可以严格要求 我们能判断它是否为冲突可串行性 如果这都满足 那肯定满足前两者 有个算法帮助我们判别冲突可串行性 ![[image235.png]] ![[image236.png]] 有事务1 2 3 所以绘制三个结点 ![[image237.png]] 第一个冲突在 ![[image238.png]] 不同事务对同一元素做涉及到写的操作 不能交换 说明2一定要在3之前执行 所以有向图中画一条2指向3的边 ![[image239.png]] 第二组冲突在 ![[image240.png]] 也是不同事务对同一元素的读写操作 1一定要在2之前做 所以画1指向2的边 ![[image241.png]] 并没有出现环 所以它是冲突可串行化的调度 ![[image242.png]] 那么到第二个问题 怎么产生一个正确的并发调度? 一样 对于并发调度不好判断 把问题转换成 如何产生一个冲突可串行化调度 ![[image243.png]] 大体来看就是用锁或者撤回实现 引入锁的概念 ### 锁 控制并发的一种手段 ![[image244.png]] 在读写任何一个数据的时候 都要事先获得锁 只有获得了锁以后 才能对这个事务进行读和写 再然后 不用这个锁的时候 要把它释放掉 因此 加上两个基本操作(同read write一样) ![[image245.png]] ![[image246.png]] 锁由调度器来管理和使用 调度器维护着一个锁表 记录着 哪个事务对哪个数据元素加了一把锁 或者 哪个事务对哪个数据元素 加了一把什么类型的锁 有了这么一个锁表 调度器就能对所有事务产生一个读写操作序列 保证事务的一致性 ![[image247.png]] 锁可以延迟一些事务的执行 一个事务对一个数据进行操作 首先要加锁 成功加上锁以后才能执行它后面的步骤 如果没加上锁 那就必然需要进行等待 一直等到其他事务对该数据元素释放了锁 当前事务才能获得锁 所以锁是用来保证冲突可串行性的 但是 锁本身并不能保证冲突可串行性 它只是一种手段 关键要看怎么去用锁(并不是有了就万事大吉 用的好才能保证) ![[image248.png]] 对于怎么用锁 就有了一系列的协议 有的协议区分锁的类型 有些不区分 那锁有哪些类型呢 ![[image249.png]] 首先简单能分为写锁和读锁 还有更复杂些的 ![[image250.png]] 如何利用不同类型的锁 既能提高并发性 又能保证一致性呢 https://www.youtube.com/watch?v=cUYPIbNYYQ0 先大略过一下 以后再研究 ![[image251.png]] ![[image252.png]] ![[image253.png]] ![[image254.png]] 加锁解锁时机 ![[image255.png]] ![[image256.png]] ![[image257.png]] ![[image258.png]] 这一块貌似跟隔离性有关系 靠 刚说就被验证了 ![[image259.png]] ![[image260.png]] ![[image261.png]] https://www.youtube.com/watch?v=-EZ2esUM8U0 中间那部分两段封锁协议暂时不管 分析一下死锁 #### 死锁 ![[image262.png]] 先执行事务1 给A上锁了 再执行事务2 给B上锁了 2执行到后面需要给A上锁 但事务1中A并没有解锁 所以得等待事务1进行解锁操作 回到事务1 执行给B上锁的操作 发现B已经被事务2上锁了 它又得等待事务2给B解锁 这样一来 1等2 2等1 形成死锁 怎么判断怎么处理 没说 据说在操作系统里会讲 哈哈 哈 …… 反正就目前这个信息比赛来说 知道什么是调度 什么是死锁就够用了 以后的事情以后再说 https://www.youtube.com/@user-gl4cn9fs5p/playlists ![[image263.png]] 有需要的时候找到这里深入 心态炸了 读锁写锁导致的死锁 麻烦死了 不管了 放弃了 真tm抽象 不管了 记答案 ![[image264.png]] ![[image265.png]] ![[image266.png]] ### 日志 **WAL(Write-Ahead Logging,预写日志)**:把事务日志先于数据更改写入持久性存储(磁盘)的事务日志技术,用于确保数据的**持久性和一致性**。核心要点: - **先写日志、后写数据**:"write ahead"即写入日志在写入数据之前执行 - **一致性与持久性**:崩溃/断电后通过重放日志还原事务状态,避免数据损坏丢失 - **数据库恢复**:启动时检查 WAL 日志,确保所有已提交事务都已应用到数据文件;未完成事务或文件损坏则用日志修复 - **性能优化**:先记内存日志、定期刷盘,减少随机磁盘写入 - **并发控制**:多事务可同时读,写操作受控以保证一致性 - SQLite、PostgreSQL、MySQL 等支持事务的数据库引擎广泛使用 ![[image267.png]] ![[image268.png]] ## 范式 ![[image269.png]] ![[image270.png]] ![[image271.png]] ![[image272.png]] ![[image273.png]] 第一范式(1NF):有主键,具有**原子性**,字段不可分割 第二范式(2NF):**完全依赖**,没有部分依赖(非主属性要依赖整个候选键) 第三范式(3NF):**没有传递依赖**(非主属性不依赖其他非主属性) - 3NF:在 2NF 的基础上,消除**非主属性对候选键的传递依赖**——表中每个非主属性必须**直接**依赖于候选键,不依赖于其他非主属性。通常要求把表拆成多个关系来满足 - BCNF(BC 范式):比 3NF 更严格——在 3NF 基础上,要求**每个非平凡函数依赖 X→Y 的决定因素 X 都必须是超键**(即左部必须包含候选键) - 层级关系:**BCNF ⊂ 3NF ⊂ 2NF ⊂ 1NF**——属于 BC 范式就一定属于第三范式 - 规范化到 BCNF 可能需要拆表,会增加查询复杂性,设计中需要权衡(备赛口径:BCNF 是"3NF 再严格一档",看到"决定因素必须是超键/候选键"选 BCNF) ![[image274.png]] 借鉴视频: https://www.bilibili.com/video/BV1Dh4y1G7cz?vd_source=f90b3e1fec7a29aa578bf2c42517c160 如何确定范式?如何范式化 先了解回顾几个概念 ![[image275.png]] 表中的一行表示 元组 表中的一列表示 属性 还有几个概念 ![[image276.png]] 码就是那种可以作为唯一区别一条元组的属性(主键、复合主键) 候选码是在码中挑的 挑那种最小集合 主码就是从候选码里面选出来的一个真正被用的(主键) 比如: 学生(学号,姓名,年龄,性别) 码:学号,姓名,(学号,姓名),(学号,年龄),(学号,性别),(学号,性别,年龄) 候选码:学号,姓名 主码:(人为挑选一个 这里选择:) 学号 做范式主要就是找这个主键(因为范式不外乎就是判断主键满足哪些要求而定的) 这样一来就很明了了 首先码不用多去管 那么第一步就是找候选码 怎么找?使用闭包(属性闭包) 找到后进行判断 当前属于什么范式 再想办法进行调整变成其他范式 ### 闭包(Closure) 先看概念(没啥用) 根据给定的一组属性集和一组函数依赖,能够推导出另一组属性的过程。 闭包用于推导属性之间的函数依赖关系,帮助数据库设计师确定关系数据库中的候选键、超键、规范化等重要概念。 主要知识点包括: 属性集:属性集是数据库表中的列或字段的集合,用于描述表的结构。 函数依赖:函数依赖是一个属性集对另一个属性集的关系。它描述了在给定属性集的情况下,其他属性集的值是如何确定的。例如,A -> B 表示属性集A的值决定了属性集B的值。 超键:超键是一个属性集,它可以唯一标识关系中的每个元组。超键的闭包包括所有属性,没有冗余属性。 候选键:候选键是超键的子集,仍然可以唯一标识关系中的每个元组。它是最小的超键。 规范化:规范化是数据库设计过程中的一步,旨在减少数据冗余并提高数据结构的清晰性和一致性。函数依赖和闭包的概念在规范化中起着重要作用,帮助设计师将数据库表分解成更小、更简单的表,以减少数据冗余。 闭包是一个属性集的完整集合,通过属性之间的函数依赖来确定。计算闭包的过程通常涉及递归,即根据已知的函数依赖,不断扩展闭包,直到无法再添加新属性为止。闭包的计算对于确定候选键、超键和规范化中的部分依赖非常重要。 知道闭包是为了求候选码(候选键)的就够了 主要是要知道怎么求 上例子: 有关系模式R(A,B,C,D) 函数依赖集F:{A->C,C->A,B->AC,D->AC,BD->A} 求(BD)的闭包 可能看不懂题目 大概解释一下 这个函数依赖集就是属性间的联系 比如A->C的意思就是 C属性是由A决定的 比如成绩是被学号确定的 要查到某人成绩肯定要根据学号查 这个就是所谓依赖关系 同理依赖关系集就是表中 属性间关系的集合 这里要求BD的闭包 那首先令X(0)为BD BD->BD (BD能推出BD没问题吧) 然后拆开来(把BD拆成B和D 再去推) X(1)=B->AC ; D->AC 又 BD->BD 所以 BD->ABCD ABCD=ABCD(R) 等于R了就说明找完了 此时ABCD就是BD的闭包 再来一个例子: 有关系模式 R(U, F) 其中 U={A,B,C,D,E,G} F={AB->C, C->A, BC->D, ACD->B, D->EG, BE->C, CG->BD, CE->AG} 求(CD)的闭包(⚠️ 原文此处写作"求 AD",但下面的推导过程与结论都是 CD,按 CD 修正) 令 X(0) = CD CD -> CD C->A、D->EG 所以 CD -> ACDEG,即 x(1) = ACDEG ACDEG ≠ ABCDEG,继续往下找——依赖集里有 ACD->B,而 ACD ⊆ ACDEG,说明能推出 B: ACDEG -> ABCDEG,即 x(2) = ABCDEG ABCDEG = R,找完了。 **所以 CD 的闭包是 ABCDEG** 当一个元素组合能推出关系中的所有元素 则称其为候选码 (换到表里面去理解 如果某主键或者某联合主键 能关系到表内所有属性 那肯定是能做主键或联合主键的) 闭包就是这样一回事 给出几个属性让你去推 如果最后能推到所有元素 就说明给的那个属性集合是候选码 反之则不是 然后就是看是第几范式 能通过闭包了肯定是有主键的 当然满足第一范式了 第二范式是没有部分依赖 第三范式是没有传递依赖 怎么判断呢 再举例 R(A,B,C,D) F{A->C,AD->B} >C AD->B AD->AD 那么AD->ABCD 所以AD为候选码 是否属于二范式?(没有部分依赖) 存在部分依赖——A->C才得到AD->C C只由A决定 不由D决定 这是部分依赖 (就像是之前的例子 学号 学生姓名 职工号 教师姓名 学生姓名只依赖于学号 教师姓名只依赖于职工号 这种部分依赖的关系 需要拆分开来) (同理 C这个字段应该被拆出去到另一个表 才能满足第二范式) 再举个贴合实际的例子 ![[image277.png]] 函数依赖:{学号->姓名 , 学号->年龄 , 学号-> 性别 , 学号->系名 , 系名->系主任, 学号、课程名->成绩} 找候选码:很容易找出 学号能推出其他所有 但学号推不出成绩 需要加上课程名才能推出所有 所以候选码是(学号,课程名) 主码是候选码选一个 只有这个就选这个咯 所以:主码:(学号,课程名) 是第几范式?找到了主键了 肯定属于第一范式 看看是不是第二范式?有没有部分依赖关系? 有吧 只有成绩需要学号加课程名推出 其他都只需要学号推出 与课程名无关 很大的一个部分依赖 然后要把它改成三范式 它连二范式都不是 更别提三范式 所以先要改成二范式(把表拆开) R1(学号,姓名,性别,年龄,系名,系主任) R2(学号,课程名,成绩) 这样一来 就都完全依赖了 看是不是三范式(有没有传递依赖) 有吧 学号推出系名 系名推出系主任 系主任跟学号没啥直接关系 这也要拆开 R1(学号,姓名,性别,年龄,系名) R2(学号,课程名,成绩) R3(系名,系主任) ![[image278.png]] ![[image279.png]] ![[image280.png]] ### BCNF (Boyce-Codd Normal Form)算法 https://b23.tv/LqzERft 讲得很好 但我听不懂 ![[image281.png]] (数据库真tm有病) (这部分的题不多 有时间回过头来研究 数据库部分只差这块了 哦还有死锁……) ![[image282.png]] ![[image283.png]] ⚠️ **此处原文粘贴过一段 AI 生成的 BCNF 分解推导,经核验有多处错误,已重写**: 给定关系模式 R(A, B, C, D, E),F={A->BC, CB->E, B->D, E->A}。 **第一步:求候选码。** - A⁺ = A → BC(A->BC)→ D(B->D)→ E(CB->E)= ABCDE ✓ **A 是候选码** - E⁺ = E → A(E->A)→ BC → D = ABCDE ✓ **E 也是候选码** - CB⁺ = C,B → E(CB->E)→ A(E->A)→ BC,D = ABCDE ✓ **CB 也是候选码** 原文说"只有一个候选键 A"——**错**,该 F 下候选码至少有 A、E、CB 三个。 **第二步:BCNF 判断标准**——对每个**非平凡**函数依赖 X→Y(Y ⊄ X),要求 **X 是超键**。逐条检查 F: - A->BC:A 是候选码 ✓ - CB->E:CB 是候选码 ✓ - B->D:B⁺={B,D} 不是超键 ✗ **违反 BCNF** - E->A:E 是候选码 ✓ **第三步:违反就拆。** 对 B->D 把 R 拆成 R1(B, D) 与 R2(A, B, C, E)……继续迭代检查(原文给出的"R1(A,B,C) + R2(C,B,E)"分解**丢了属性 D,且未保住 B->D 依赖,不能通过无损连接恢复原关系**,不可用)。 > (这部分的题不多,有时间回过头来研究——数据库部分只差这块了,哦还有死锁……) ## 存储 **RAID(冗余独立磁盘阵列)**:把多个磁盘组合成一个独立存储系统,提高可用性和性能。不同级别提供不同的冗余与性能权衡: | 级别 | 原理 | 优点 | 缺点 | |---|---|---|---| | RAID 0(条带化) | 数据分块分布到多盘,读写并行 | 高性能、大容量 | **无冗余**,坏一块全丢;不适合重要数据 | | RAID 5 | 数据+校验信息分布到不同磁盘,单盘故障可重建 | 性能好、容错(坏 1 块不丢数据) | 写入要算校验,性能略低;**至少 3 块盘** | | RAID 10(RAID 1+0) | 先镜像(RAID 1)再条带化(RAID 0) | 高性能+高容错,可坏多块(不同镜像组) | 空间开销大(镜像);**至少 4 块盘** | 选型口径:非关键数据求性能选 RAID 0,要一定冗余选 RAID 5,关键数据求高性能+高容错选 RAID 10。 ![[image284.png]] ![[image285.png]] **缓冲池(buffer pool)与脏页**:DBMS 用缓冲池管理内存中的页,每页有 pin_count(固定计数)和 dirty(脏标记)两个属性。 - pin_count = 0:不再被任何事务/操作引用 - dirty = true:页面已被修改,内容与磁盘不一致("**脏页**") - 替换脏页时必须**先写回磁盘**——否则崩溃/断电时未落盘的更改会丢失,破坏持久性与一致性 - 实际系统会用延迟写入、脏页队列、检查点等策略优化写盘开销 ![[image286.png]] ## 其他 ![[image287.png]] ![[image288.png]] ![[image289.png]] ![[image290.png]] ![[image291.png]] ![[image292.png]] ⬅️ [[05-数据结构|上一篇]] 🏠 [[00-信息基础大赛]] ➡️ [[07-计算机网络|下一篇]]