(三)MySQL之库表设计篇:一、二、三、四、五范式、BC范式与反范式详解!

发布时间:2026/7/18 10:10:06
(三)MySQL之库表设计篇:一、二、三、四、五范式、BC范式与反范式详解! 引言MySQL的库表设计在很多时候我们都是率性而为往往在前期的设计中考虑并不全面同时对于库表结构的划分也并不明确所以很多时候在开发过程中代码敲着敲着会去重构某张表结构甚至大面积重构多张表结构这种随心所欲的设计方式无疑给开发造成了很大困扰。范式但实际上设计DB库表结构时也有一些共同需要遵守的规范这些规范在数据库设计中被称为“范式”理解并掌握这些设计时的规范能让咱们在项目之初设计的库表结构更为合理且优雅。数据库范式中声名远扬的有三大范式但除此之外也有一些其他设计规范如• ①数据库三大范式1NF、2NF、3NF• ③第四范式(4NF和第五范式完美范式5NF• ②巴斯-科德范式BCNF• ④反范式设计不过对于上述的几种设计范式大部分小伙伴应该仅了解过三范式对于其他的应该未曾接触那在本篇中会重点阐述库表设计时会用到的这些范式。一、数据库三大范式范式(Normal Form)在前面也提到过它就是指设计数据库时要遵守的一些原则而数据库的三大范式相信诸位在学习数据库知识时也定然接触过。三大范式之间它们是递进的关系也就是后续的范式都基于前一个范式的基础上推行就好比下面这句话今天我要先炒菜然后吃饭最后洗碗。炒菜、吃饭、洗碗三者也属于递进关系后者都建立在前者之上其顺序不能颠倒比如先吃饭再炒菜这必然是行不通的。数据库的三大范式也一样第二范式必须建立在第一范式的基础之上如若设计的库表第一范式都不满足那定然是无法满足第二范式的。写在前面的话其实对于数据库三范式相关的资料网上也有很多很多但大部分资料都涉及了太多的概念通篇看下来也很难让人理解因此下述的三范式则会结合具体的设计实例来让诸位彻底理解三范式。1.1、第一范式1NF库表设计时的第一范式主要是为了确保原子性的也就是存储的数据具备不可再分性这话咋理解呢上个案例SELECT * FROM zz_student; ------------------------------------- | student | course | score | ------------------------------------- | 竹子男185cm | 语文 | 95 | | 竹子男185cm | 数学 | 100 | | 竹子男185cm | 英语 | 88 | | 熊猫女170cm | 语文 | 99 | | 熊猫女170cm | 数学 | 90 | | 熊猫女170cm | 英语 | 95 | -------------------------------------在上述的学生表中其中有一个student学生列这一列存储的数据则明显不符合第一范式原子性的规定因为这一列的数据还可以再拆分为姓名、性别、身高三项数据因此为了符合第一范式应该将表结构更改为---------------------------------------------------------- | student_name | student_sex | student_height | course | score | ---------------------------------------------------------- | 竹子 | 男 | 185cm | 语文 | 95 | | 竹子 | 男 | 185cm | 数学 | 100 | | 竹子 | 男 | 185cm | 英语 | 88 | | 熊猫 | 女 | 170cm | 语文 | 99 | | 熊猫 | 女 | 170cm | 数学 | 90 | | 熊猫 | 女 | 170cm | 英语 | 95 | ----------------------------------------------------------将student这一列数据分别拆分为姓名、性别、身高三列然后分别存储对应的数据才合理通过这样的优化后此时zz_student这张表则符合了数据库设计的第一范式。那此刻思考一下如果不去拆分列满足第一范式会造成什么影响呢• 客户端语言和表之间无法很好的生成映射关系。• 查询到数据后需要处理数据时还需要对student字段进行额外拆分。• 插入数据时对于第一个字段的值还需要先拼装后才能进行写入。简单来说如果按照原本那张形式去做业务开发显然操作起来会更加麻烦且复杂一些但第一范式的原子性除开对列级别生效之外行级别的数据也是同理也就是每一行数据之间是互不影响的都是独立的一个整体。1.2、第二范式2NF上述的第一范式还是比较容易理解紧接着来看看第二范式第二范式的要求表中的所有列其数据都必须依赖于主键也就是一张表只存储同一类型的数据不能有任何一列数据与主键没有关系还是上面的那张表数据为例---------------------------------------------------------- | student_name | student_sex | student_height | course | score | ---------------------------------------------------------- | 竹子 | 男 | 185cm | 语文 | 95 | | 竹子 | 男 | 185cm | 数学 | 100 | | 竹子 | 男 | 185cm | 英语 | 88 | | 熊猫 | 女 | 170cm | 语文 | 99 | | 熊猫 | 女 | 170cm | 数学 | 90 | | 熊猫 | 女 | 170cm | 英语 | 95 | ----------------------------------------------------------虽然此时已经满足了数据库的第一范式但此刻观察course课程、score分数这两列数据跟前面的几列数据实际上依赖关系并不大同时也由于这样的结构导致前面几列的数据出现了大量冗余所以此时可以再次拆分一下表结构SELECT * FROM zz_student; -------------------------------------------------------------- | student_id | name | sex | height | department | dean | -------------------------------------------------------------- | 1 | 竹子 | 男 | 185cm | 计算机系 | 竹子老大 | | 2 | 熊猫 | 女 | 170cm | 金融系 | 熊猫老大 | -------------------------------------------------------------- SELECT * FROM zz_course; ------------------------ | course_id | course_name | ------------------------ | 1 | 语文 | | 2 | 数学 | | 3 | 英语 | ------------------------ SELECT * FROM zz_score; ---------------------------------------- | score_id | student_id | course_id | score | ---------------------------------------- | 1 | 1 | 1 | 95 | | 2 | 1 | 2 | 100 | | 3 | 1 | 3 | 88 | | 4 | 2 | 1 | 99 | | 5 | 2 | 2 | 90 | | 6 | 2 | 3 | 95 | ----------------------------------------经过上述结构优化后之前的一张表此时被我们拆分成学生表、课程表、成绩表三张每张表中的id字段作为主键其他字段都依赖这个主键。无论在那张表中都可以通过id主键确定其他字段的信息。主键可以不用id但最好是自增的主键ID这跟索引有关后续索引篇详细讲解。此时再将目光看到先后两张学生表原本的学生表有六条学生记录其中有四条是冗余数据此时的学生表则只有两条数据同时这张学生表中只存储学生信息相关的数据。经过本次结构优化后每张表的业务属性都具备“唯一性”也就是每张表都只会描述了“一件事情”不会存在一张表中会出现两个业务属性例如之前的学生表包含了学生信息和课程成绩。1.3、第三范式3NF前面已经对第一范式、第二范式进行了直观阐述接下来聊一聊数据库的第三范式第三范式要求表中每一列数据不能与主键之外的字段有直接关系怎么理解呢基于上述的例子-------------------------------------------------------------- | student_id | name | sex | height | department | dean | -------------------------------------------------------------- | 1 | 竹子 | 男 | 185cm | 计算机系 | 竹子老大 | | 2 | 熊猫 | 女 | 170cm | 金融系 | 熊猫老大 | --------------------------------------------------------------比如这张学生表目前即符合第一范式也符合第二范式但看最后的两个字段department表示当前学生所属的院校dean则表示这个院系的院长是谁。一般来说一个学生的院长是谁首先是取决于学生所在的院系的因此最后的dean字段明显与department字段存在依赖关系因此需要进一步调整表结构SELECT * FROM department; ------------------------------------------------- | department_id | department_name | department_dean | ------------------------------------------------- | 1 | 计算机系 | 竹子老大 | | 2 | 金融系 | 熊猫老大 | ------------------------------------------------- SELECT * FROM zz_student; ------------------------------------------------- | student_id | name | sex | height | department_id | ------------------------------------------------- | 1 | 竹子 | 男 | 185cm | 1 | | 2 | 熊猫 | 女 | 170cm | 2 | -------------------------------------------------经过进一步的结构优化后又将原本的学生表拆为了院系表、学生表两张学生表中则是只存储一个院系ID由院系表存储院系相关的所有数据。至此学生表中的每个非主键字段与其他非主键字段之间都是相互独立的之间不会再存在任何依赖性所有的字段都依赖于主键。那这里为什么要调整呢不调整不行吗还真不行来简单思考一下不调整结构的情况下会发生什么问题• ①当一个院系的院长换人后需要同时修改学生表中的多条数据。• ②当一个院长离职后需要删除该院长的记录会同时删除多条学生信息。• ......也就是如果设计的表结构无法满足第三范式在操作表时就会出现异常使得整个表较难维护。1.4、数据库三范式小结到这里就已经将库表设计的三范式做了直观阐述总结如下• 第一范式确保原子性表中每一个列数据都必须是不可再分的字段。• 第二范式确保唯一性每张表都只描述一种业务属性一张表只描述一件事。• 第三范式确保独立性表中除主键外每个字段之间不存在任何依赖都是独立的。经过三范式的示例后数据库中的表数量也逐渐多了起来似乎设计符合三范式的库表结构反而更加麻烦了对吗答案并非如此因为在没有按照范式设计时会存在几个问题• ①整张表数据比较冗余同一个学生信息会出现多条。• ②表结构特别臃肿不易于操作要新增一个学生信息时需添加大量数据。• ③需要更新其他业务属性的数据时比如院系院长换人了需要修改所有学生的记录。但按照三范式将表结构拆开后假设要新增一条学生数据就只需要插入学生相关的信息即可同时如果某个院系的院长换人了只需要修改院系表中的院长就行学生表中的数据无需发生任何更改。因此经过三范式的设计优化后整个库中的所有表结构会显得更为优雅灵活性也会更强。二、巴斯-科德范式与第四、五范式第一阶段中简单了解了库表设计时最基本的三大范式但除此之外还有另外三种设计范式即巴斯-科德范式与第四、第五范式这后续三种范式可能有很多小伙伴没接触过但当你尝试从网上去了解时相信绝大部分能看到的资料你都看不懂例如BCNF观察上图中的描述这一眼望过去几乎不是给人看的没有诋毁的意思单纯感慨~其中涉及的码、完全函数依赖等名词至少刚接触的小白是读不懂的因此接下来则依旧采用上面那种案例大白话的模式简单阐述一下这三种设计范式。2.1、巴斯-科德范式BCNF在了解后续这些范式之前首先得弄明白一个概念一般在一张表中可以用于区分每行数据的一个列通常会被咱们设为主键例如常用的ID字段就是如此这类主键通常被称为单一主键即一个列组成的主键。但除此之外还有一个联合主键的概念也就是由多个列组成的主键相信这点大家在学习数据库的时候也接触过。巴斯-科德范式也被称为3.5NF至于为何不称为第四范式这主要是由于它是第三范式的补充版第三范式的要求是任何非主键字段不能与其他非主键字段间存在依赖关系也就是要求每个非主键字段之间要具备独立性。而巴斯-科德范式在第三范式的基础上进一步要求任何主属性不能对其他主键子集存在依赖。对于上述的范式定义大家估计有些晕那用大白话说简单一点也就是规定了联合主键中的某列值不能与联合主键中的其他列存在依赖关系相信这样讲大家更加容易理解。当然还是结合一个案例阐述。先来看一张表-------------------------------------------------------- | classes | class_adviser | name | sex | height | -------------------------------------------------------- | 计算机-2201班 | 熊竹老师 | 竹子 | 男 | 185cm | | 金融-2201班 | 竹熊老师 | 熊猫 | 女 | 170cm | | 计算机-2201班 | 熊竹老师 | 子竹 | 男 | 180cm | --------------------------------------------------------例如这张学生表此时假设以classes班级字段、class_adviser班主任字段、name学生姓名字段组合成一个联合主键在这里我们可以通过联合主键确定学生表中任何一个学生的信息比如熊竹老师管的计算机-2201班哪个竹子同学有多高啊对于这个问题可以通过上述的联合主键精准定位到表中第一条数据并且最终能够给出答案为185cm。当然在这里有小伙伴有疑惑为什么这三个字段可以组成联合主键和其他字段例如身高、性别就不行呢因为主键一般都是用于区分不同行数据的必须要确保唯一性假设以「班级、班主任、性别」三个字段作为联合主键此时能通过这个联合主键精准定位到每一条数据吗答案是NO上个例子理解熊竹老师管的计算机-2201班哪个男同学有多高啊现在以这个联合主键还能精准定位到每一条数据吗不行的因为表中有两位男同学所以会扫描到多条数据最终会得到185cm、180cm两个答案显然「班级、班主任、性别」这三个字段具备重复性不适合作为主键。到这里咱们分析一下假设以「班级、班主任、学生姓名」三个字段组成联合主键当前这张表是否符合前面的三大范式呢• 第一范式表中每列数据都不可再分具备原子性满足。• 第二范式表中每行数据都仅描述了学生信息这一种业务属性具备唯一性满足。• 第三范式除主键外表中非主键字段之间都不存在依赖关系具备独立性满足。经过上述分析后当前这张表也符合前面聊到的三大范式但没有问题了吗有的在这张表中一条学生信息中的班主任取决于学生所在的班级比如「竹子同学、子竹同学」在「计算机-2201班」所以它们的班主任都是「熊竹老师」因此班主任字段其实也依赖于班级字段。那会造成什么问题呢• ①当一个班级的班主任老师换人后需要同时修改学生表中的多条数据。• ②当一个班主任老师离职后需要删除该老师的记录会同时删除多条学生信息。• ③想要增加一个班级时同时必须添加学生姓名数据因为主键不允许为空。通过上述分析可以明显得知如果联合主键中的一个字段依赖于另一个字段同样也会造成不小的问题使得整张表的维护性变差因此这里需要进一步调整结构SELECT * FROM zz_classes; ---------------------------------------------- | classes_id | classes_name | class_adviser | ---------------------------------------------- | 1 | 计算机-2201班 | 熊竹老师 | | 2 | 金融-2201班 | 竹熊老师 | ---------------------------------------------- SELECT * FROM zz_student; ---------------------------------- | classes_id | name | sex | height | ---------------------------------- | 1 | 竹子 | 男 | 185cm | | 2 | 熊猫 | 女 | 170cm | | 1 | 子竹 | 男 | 180cm | ----------------------------------经过结构调整后原本的学生表则又被拆为了班级表、学生表两张在学生表中只存储班级ID然后使用classes_id班级ID和name学生姓名两个字段作为联合主键。实际情况中学生表应该有学生ID字段作为主键因为同一个班级中也有可能会出现重名的现象但这里是为了举例说明不要纠结细节~此时经过调整后目前的学生表也满足了巴斯-科德范式同时对于前面列出的三个问题调整结构后也不复存在比如换班主任后只需要更改班级表无需修改学生表中的学生信息增加班级时只需要在班级表中新增数据也不会影响学生表。在这里更专业的做法应该是对于班级表中的班主任老师信息再进一步抽象出一张教师表。毕竟班主任字段还依旧与班级字段存在依赖关系但班级表中的主键却是班级ID所以非主键字段之间存在关联是不满足第三范式的但这里大家清楚就好啦我就不做了。OK经过上述一个案例的剖析后大家对巴斯-科德范式也有了全面的认知至于它为何被叫做3.5范式相信大家也能够想清楚答案因为巴斯-科德范式并没有定义新的设计规范仅是对第三范式的做了补充及完善修正了第三范式。第三范式只要求非主键字段之间不能存在依赖关系但没要求联合主键中的字段不能存在依赖因此第三范式并未考虑完善巴斯-科德范式修正的就是这点。2.2、第四范式4NF认识了巴斯-科德范式后再来看看数据库的第四范式第四范式是基于BC范式之上的但在理解第四范式之前首先得理解“多值依赖”的概念先贴一下学术论文中常见的定义多值依赖论文来源于《道客巴巴-多值依赖》大部分网上资料的描述也都来自于这些学术论文。能看明白嘛看不明白就对了对于这种概念看起来确实令人头大没有相关的技术知识储备就算挠破头皮也看不懂这段描述因此简单说一下什么叫做多值依赖一个表中至少需要有三个独立的字段才会出现多值依赖问题多值依赖是指表中的字段之间存在一对多的关系也就是一个字段的具体值会由多个字段来决定。这样写出来似乎比前面好理解一些了但相对来说还是很绕那就再上个例子SELECT * FROM zz_user_role_permission; ---------------------------------------- | user_name | user_sex | role | permission | ---------------------------------------- | 竹子 | 男 | ROOT | * | | 熊猫 | 女 | ADMIN | BACKSTAGE | | 竹子 | 男 | ADMIN | BACKSTAGE | | 熊猫 | 女 | USER | LOGIN | | 竹子 | 男 | USER | LOGIN | | 子竹 | 男 | USER | LOGIN | ----------------------------------------上述是一个经典的业务也就是一张用户角色权限表先简单介绍一下表中各字段的信息•user_name字段 -- 用户名•role字段 -- 角色信息•USER普通用户角色。•ADMIN管理员角色。•ROOT超级管理员角色。•permission字段 -- 权限信息•*超级管理员拥有的权限级别*表示所有。•BACKSTAGE管理员拥有的权限级别表示可以操作后台。•LOGIN普通用户拥有的权限级别表示可以登录访问平台。理解各字段的值后假设以「用户名、角色、权限」三个字段作为联合主键先来分析一下这张表是否满足之前的范式• 表中每列数据都不可再分具备原子性满足第一范式。• 表中数据都仅描述了用户权限这一种业务属性具备唯一性满足第二范式。• 除主键外表中其他字段不存在依赖关系具备独立性满足第三范式。• 联合主键中的用户、角色、权限都为独立字段不存在依赖性满足BC范式。因为表中除开联合主键外就剩下了一个性别字段因此非主键字段必然是独立的所以满足第三范式但对于BC范式仅是勉强满足因为「用户、角色、权限」之间存在一些依赖关系不过这里先不管毕竟是举例说明因此假设是满足BC范式。上述的表结构介绍清楚后现在来聊聊什么叫做多值依赖。此时假设我们需要新增一条数据那表中的权限字段究竟填什么这个值是需要依赖多个字段决定的权限来自于角色而角色则来自于用户。也就是说一个用户可以拥有多个角色同时一个角色可以拥有多个权限所以此时咱们无法单独根据用户名去确定权限值权限值必须依赖用户、角色两个字段来决定这种一个字段的值取决于多个字段才能确定的情况就被称为多值依赖。到这里是不是就理解了多值依赖再举个例子也就是网上经典的例子。SELECT * FROM zz_course_scheduling; ------------------------------------------------------------- | course | classes | teacher | book | ------------------------------------------------------------- | 语文 | 计算机一班 | 竹熊老师 | 人教版-新课标教材 | | 语文 | 计算机二班 | 黑竹老师 | 人教版-现行教材 | | 语文 | 计算机三班 | 竹熊老师 | 北师大版教材 | | 数学 | 计算机一班 | 熊竹老师 | 人教版-新课标教材 | | 英语 | 计算机一班 | 黑熊老师 | 人教版-新课标教材 | -------------------------------------------------------------上述是一张教师排课表分别有课程、班级、老师、教材四个字段一个课程会有多位老师授课同时一个课程也会有多个版本的教材此时就无法只根据课程、班级、老师任一字段决定教材字段的值而是要结合班级、课程、老师三个字段才能确定教材字段的值比如计算机一班的语文课程竹熊老师来上用的是人教版-新课标教材因此目前教材字段也存在多值依赖的问题依赖于班级、课程、老师三个字段。再经过一个案例的熏陶后是不是对多值依赖的概念理解更深刻啦~到这里为止多值依赖的概念就讲清楚了也正是由于多值依赖的情况出现又会导致表中出现时数据冗余、新增、删除异常等问题出现。因此第四范式的定义就是要消除表中的多值依赖关系。怎么做呢拿前面的权限表举例。SELECT * FROM zz_users; ------------------------------------------------------------- | user_id | user_name | user_sex | password | register_time | ------------------------------------------------------------- | 1 | 熊猫 | 女 | 6666 | 2022-08-14 15:22:01 | | 2 | 竹子 | 男 | 1234 | 2022-09-14 16:17:44 | | 3 | 子竹 | 男 | 4321 | 2022-09-16 07:42:21 | ------------------------------------------------------------- SELECT * FROM zz_roles; ----------------------------------------- | role_id | role_name | created_time | ----------------------------------------- | 1 | ROOT | 2022-08-14 15:12:00 | | 2 | ADMIN | 2022-08-14 15:12:00 | | 3 | USER | 2022-08-14 15:12:00 | ----------------------------------------- SELECT * FROM zz_permissions; ----------------------------------------------------- | permission_id | permission_name | created_time | ----------------------------------------------------- | 1 | * | 2022-08-14 15:12:00 | | 2 | BACKSTAGE | 2022-08-14 15:12:00 | | 3 | LOGIN | 2022-08-14 15:12:00 | ----------------------------------------------------- SELECT * FROM zz_users_roles; ---------------------- | id | user_id | role_id | ---------------------- | 1 | 1 | 1 | | 2 | 1 | 2 | | 3 | 1 | 3 | | 4 | 2 | 2 | | 5 | 2 | 3 | | 6 | 3 | 3 | ---------------------- SELECT * FROM zz_roles_permissions; ---------------------------- | id | role_id | permission_id | ---------------------------- | 1 | 1 | 1 | | 2 | 2 | 2 | | 3 | 3 | 3 | ----------------------------观察上述的五张表如果有做过权限设计或用过Shiro框架的小伙伴应该会感到额外的亲切这个正是大名鼎鼎的权限五表将原本的用户角色权限表拆分成了用户表、角色表、权限表、用户角色关系表、角色权限关系表。经过这次拆分之后一方面用户表、角色表、权限表中都不会有数据冗余第二方面无论是要删除亦或新增一个角色、权限时都不会影响其他表。后面的两张关系表主要是为了维护用户、角色、权限三者之间的关系。对于前面的教师排课表就不再拆分啦大家如若想要锻炼一下掌握程度可自行将其拆分成符合第四范式的表结构。2.3、第五范式5NF/完美范式了解了第四范式后再来看看第五范式这个范式也被称为完美范式先来说一下第五范式的定义建立在4NF的基础上进一步消除表中的连接依赖直到表中的连接依赖都是主键所蕴含的。等等连接依赖又是个啥连接依赖看不懂对不说实话我也看着迷糊大概能确定的是多值依赖也属于连接依赖的一种而连接依赖也包含了多值依赖大家可以参考一下《这个》。第五范式解决的是无损连接问题但对于第五范式我自个儿也没理解透彻因此不再讲解第五范式了防止误导诸位同时如若有对这块十分了解的大佬可以留言指点一下。2.4、六大范式小结经过一系列的阐述后其实不难发现越到后面的范式越难令人理解同时为了让表满足更高级别的范式越往后付出代价也越大而且拆分出的表数量也会越多所以一般实际开发中对于库表的设计最高满足BC范式即可再往后就没意义了因为表数量一多查询也好写入也罢性能会越来越差。同时由于后面的几种范式在实际项目中应用较少因此关于这块的资料也会较少后续的几种范式也仅有一些学术机构在琢磨所以当我们试图去窥探时能看到的也是一堆学术词汇。除开聊到的六大范式外还有一种范式名为域键范式也被称之为终极范式但目前也仅有学术机构在研究在生产环境中实际的用途也不大诸位有兴趣可以自己看看最后再上一个各范式之间的递进关系图七大范式• 第一范式原子性每个字段的值不能再分。• 第二范式唯一性表内每行数据必须描述同一业务属性的数据。• 第三范式独立性表中每个非主键字段之间不能存在依赖性。• 巴斯范式主键字段独立性联合主键字段之间不能存在依赖性。• 第四范式表中字段不能存在多值依赖关系。• 第五范式表中字段的数据之间不能存在连接依赖关系。• 域键范式试图研究出一个库表设计时的终极完美范式。三、数据库反范式设计遵循数据库范式设计的结构优点很明显它避免了大量的数据冗余节省了大量存储空间同时让整体结构更为优雅能让SQL操作更加便捷且减少出错。但随着范式的级别越高设计出的结构会更加精细化原本一张表的数据会被分摊到多张表中存储表的数量随之越来越多。但随之而来的不仅仅只有好处也存在一个致命问题也就是当同时需要这些数据时只能采用联表查询的形式检索数据有时候甚至为了一个字段的数据也需要做一次连表查询才能获得。这其中的开销无疑是花费巨大的尤其是当连接的表不仅两三张而是很多张时有可能还会造成索引失效这种情况带来的资源、时间开销简直是一个噩梦这会严重地影响整个业务系统的性能。因此也正是由于上述一些问题在设计库表结构时我们不一定要100%遵守范式准则。这种违反数据库范式的设计方法就被称之为反范式设计。遵循范式设计也好反范式设计也罢本身两者之间并没有优劣之分只要能够对业务更有利那就可以称之为好的设计方案。范式的目的仅在于让我们设计的结构更优雅合理有时候在表中多增加一个字段从数据库的角度来看数据会存在冗余问题会让表结构违反范式的定义但如若能够在实际情况中减少大量的连表查询这种设计自然也是可取的。也就是说在设计时千万不要拘泥于规则之内一定要结合实际业务考虑遵循业务优先的原则去设计结构。当然对于反范式设计也无需再用更多的语言去描述了因为本质上就是一个概念词也就是不遵循数据库范式设计的结构就被称为反范式结构。不过要牢记的一点是不是所有不遵循数据库范式的结构设计都被称为反范式反范式设计是指自己知道会破坏范式但对业务带来好处大于坏处时刻意设计出破坏范式的结构。随意设计出的结构不满足范式要求同时还无法给业务上带来收益的这并不被称为反范式设计反范式设计是一种刻意为之的思想。四、库表设计篇总结在本篇中详细阐述了DB库表设计时的一些思想也就是范式与反范式设计理论这些理论仅仅只是一套方法论实际开发过程中还是需要根据业务来设计出最合适的结构。在文中提及了六种范式但一般项目中仅需满足到第三范式或BC范式即可因为这个度刚刚好再往后就会因为过于精细化设计导致整体性能反而下降。控制到第三范式的级别一方面数据不会有太多冗余第二方面也不会对性能影响过大。同时如若打破范式的设定能对业务更有利那也可以违背范式原则去设计。不过虽说这些属于方法论但认真看下来之后相信诸位在之后设计库表结构应该会潜意识的遵循一些范式原则也会尽量的将表结构设计的更为优雅从而也能让咱们在开发过程中减少调整库表结构的次数和带来的影响。一般而言库表结构设计的是否合理区别如下• 不合理的结构设计会造成的问题• 数据冗余会浪费一定程度上的存储空间• 不便于常规SQL操作例如插入、删除甚至会出现异常• 合理的结构设计带来的好处• 节省空间SQL执行时能节省内存空间数据存储时能节省磁盘空间• 数据划分较为合理DB性能整体较高并且数据也非常完整• 结构便于维护和进行常规SQL操作