数据库三大范式:从概念到实战,一篇文章彻底搞懂
为什么你的表设计总出问题为什么数据冗余、更新异常、插入异常、删除异常频频发生很可能是范式没用好。今天我们用最通俗的语言把这三大范式讲清楚、讲透彻。数据库设计是一门艺术而范式就是这门艺术的“基本法”。掌握三大范式不仅能让你设计出结构清晰、冗余低、易维护的数据库还能帮你理解很多高级设计思想。今天我们就来一场范式之旅。一、范式是什么为什么需要它范式Normal Form是关系型数据库中用于规范化表结构的一套理论准则目的是减少数据冗余、避免更新异常、插入异常和删除异常。异常现象举例一个设计糟糕的表学号姓名系名系主任课程号课程名成绩101张三计算机系王教授C001数据库85101张三计算机系王教授C002操作系统90102李四数学系李教授C001数据库78问题数据冗余张三的系名和系主任重复存储。更新异常如果计算机系主任换成张教授需要更新多行容易遗漏。插入异常一个新系还没招学生就无法插入系主任信息因为主键需要学号课程号。删除异常如果张三退选所有课程他的系信息也会被删除。范式的目标就是通过分解表来消除这些问题。二、第一范式1NF原子性列不可再分2.1 定义第一范式要求表中的每一列都是不可再分的基本数据项即每个属性值都是原子的。2.2 违反 1NF 的例子学号姓名联系方式101张三电话: 138****, 邮箱: zhangsanxx.com“联系方式”列包含了电话和邮箱两个信息不满足原子性。应该拆分为两列学号姓名电话邮箱2.3 常见误区复合属性如地址拆分为省、市、街道需要根据业务需求决定是否拆分不一定必须拆但拆了更符合 1NF。1NF 只要求列不可分不要求消除重复组那是更高范式的事。实际上任何一张符合关系数据库定义的表默认都满足 1NF因为关系模型要求属性是原子的。所以我们通常从 2NF 开始讨论。三、第二范式2NF消除部分依赖3.1 前置知识完全函数依赖 vs 部分函数依赖完全函数依赖主键的所有列一起才能决定某个非主属性。部分函数依赖主键中的一部分列就能决定某个非主属性。例子表(学号, 课程号) - 成绩是联合主键。成绩依赖于完整的学号课程号这是完全依赖。但如果还有“学生姓名”列姓名只依赖于学号不依赖于课程号这就是部分依赖。3.2 第二范式定义第二范式在满足 1NF 的基础上消除非主属性对主键的部分依赖。3.3 违反 2NF 的例子选课表学号课程号学生姓名系名成绩101C001张三计算机85101C002张三计算机90主键是学号课程号。非主属性“学生姓名”只依赖于学号不依赖于课程号 → 部分依赖。同样“系名”也只依赖于学号。问题数据冗余每个课程都重复存储姓名和系名更新异常修改姓名需要改多行。3.4 分解达到 2NF将表拆分为两张学生表(学号, 学生姓名, 系名)主键学号。选课表(学号, 课程号, 成绩)主键学号课程号。这样学生信息只存储一次消除冗余。四、第三范式3NF消除传递依赖4.1 传递依赖定义如果非主属性 B 依赖于主键 A而另一个非主属性 C 又依赖于 B则 C传递依赖于 A。4.2 第三范式定义第三范式在满足 2NF 的基础上消除非主属性对主键的传递依赖。4.3 违反 3NF 的例子学生表已经满足 2NF学号学生姓名系号系名系主任101张三D01计算机系王教授102李四D01计算机系王教授103王五D02数学系李教授主键是学号。非主属性“系名”和“系主任”依赖于“系号”而“系号”又依赖于“学号”学号 → 系号 → 系名。这就是传递依赖。问题冗余计算机系的系名和主任重复存储更新异常修改系主任需要更新多条记录。4.4 分解达到 3NF再拆分为两张表学生表(学号, 学生姓名, 系号)系号作为外键。系表(系号, 系名, 系主任)。这样系信息只存储一次消除传递依赖。五、三大范式总结表范式核心要求消除的依赖目标1NF列不可分原子性—确保每一列都是基本数据项2NF消除部分依赖非主属性对主键的部分依赖确保每个非主属性完全依赖于整个主键3NF消除传递依赖非主属性之间的传递依赖确保非主属性之间相互独立只依赖于主键记忆口诀1NF列不可分2NF全依赖主键3NF不依赖其他非主键六、范式不是越高越好反范式化6.1 范式的代价表拆分越多查询时需要的JOIN 操作就越多性能可能下降。在某些读远多于写的场景如数据仓库、报表系统适度的反范式化故意保留冗余可以大幅提升查询效率。6.2 反范式化应用举例电商订单场景遵循 3NF订单表只存用户 ID查询订单详情需要 JOIN 用户表获取用户名、地址。反范式订单表直接冗余存储“用户姓名”、“收货地址”快照。虽然更新用户信息时需要同步或容忍不一致但查询订单历史时无需 JOIN速度更快。6.3 设计原则核心原则以业务需求为导向在范式与性能之间取得平衡。通常OLTP在线事务处理系统建议遵循 3NFOLAP在线分析处理系统可以适当反范式化。七、扩展BCNF、第四范式、第五范式三大范式已经能满足绝大多数设计需求。简要提及更高级的范式BCNF巴斯-科德范式在 3NF 基础上消除主属性对候选键的部分/传递依赖处理多个候选键的情况。实际中很少遇到违反 BCNF 但仍满足 3NF 的表。第四范式4NF消除多值依赖。第五范式5NF消除连接依赖。在实际工程中达到 3NF 通常已经足够。八、实战设计示例从非规范化到 3NF假设要设计一个简单的“学生选课系统”。初始宽表未规范化学号学生姓名系名系主任课程号课程名成绩第一步确保 1NF其实这张表已经原子性没问题。第二步达到 2NF。找出部分依赖学生姓名、系名、系主任只依赖学号不依赖课程号。拆分为学生(学号, 姓名, 系名, 系主任)选课(学号, 课程号, 课程名, 成绩)第三步达到 3NF。学生表中系名和系主任传递依赖于学号学号→系名? 不应该是学号→系号→系名。但这里没有系号直接依赖实际上“系名”和“系主任”是关联的如果系名改变系主任也可能改变。它们依赖于隐含的“系号”。因此再拆分学生(学号, 姓名, 系号)系(系号, 系名, 系主任)选课(学号, 课程号, 成绩)课程(课程号, 课程名)最终得到 3NF 设计。九、常见面试题及答案Q1满足 3NF 的表一定满足 2NF 吗A是的3NF 是在 2NF 基础上的加强。Q2主键只有一个列的表最低满足第几范式A如果主键是单列则不可能存在部分依赖所以至少满足 2NF。至于是否满足 3NF要看有无传递依赖。Q3什么是候选键、主键、外键A候选键是能唯一标识一行的最小属性集合主键是选中的一个候选键外键是引用其他表主键的列。Q4实际项目中是否必须严格遵循 3NFA不一定。要根据读写比例、查询复杂度综合权衡。通常建议以 3NF 为起点在性能瓶颈处适度反范式化。十、总结三大范式是数据库设计的基石1NF列不可分这是底线。2NF消除部分依赖让所有字段完全依赖主键。3NF消除传递依赖让字段只依赖主键。它们帮助我们构建结构清晰、冗余可控、维护简单的数据库。但范式不是教条灵活运用、结合实际业务才是高手之道。如果觉得有帮助欢迎点赞、收藏、转发本文首发于 CSDN未经授权禁止转载。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2548713.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!