一、范式
1.概念与意义
范式(Normal Form)是数据库设计需遵循的规范,解决"设计随意导致后期重构困难"问题。主流有 三大范式(1NF、2NF、3NF),还有进阶的 BCNF、4NF、5NF 等,范式间是递进依赖(如 2NF 基于 1NF,3NF 基于 2NF )。
2.第一范式(1NF)
(1)**规则:**字段需满足原子性(不可再拆分)
(2)示例:

如图,学生表中"student"字段列存储的数据,明显还可拆分为姓名、性别、身高,拆分后才符合 1NF。所以应将表结构更改为下图,才符合1NF:

(3)不满足1NF的影响:
客户端语言和表之间无法很好的生成映射关系
查询到数据后,需要处理数据时,还需要对其字段进行额外拆分
插入数据时,对于第一个字段的值还需要先拼装后才能进行写入
3.第二范式(2NF)
(1)**规则:**满足1NF的基础上,表中所有列必须完全依赖主键(一张表只描述一类业务,无冗余关联)。
(2)**示例:**观察1NF中表中 course 、 score 这两列数据,跟前面的几列数据实际上依赖关系并不大,所以此时在1NF表基础上可以再次拆分一下表结构:
student 表

course 表

score 表

结构优化后,之前的一张表被拆分成学生表、课程表、成绩表三张,每张表中的 id 字段作为主键,其他字段都依赖这个主键。无论在那张表中,都可以通过id
主键确定其他字段的信息,每张表的业务属性都具备"唯一性"。
(3)不满足2NF的影响:
因字段对主键存在部分依赖,会导致:数据冗余(部分信息重复存)
更新异常(改一处需动多条)
插入/删除异常(操作受主键关联限制,易出错)
4.第三范式(3NF)
(1)**规则:**满足2NF的基础上,非主键字段不传递依赖于主键(字段间独立,无间接依赖)。
(2)**示例:**观察2NF中 student 表,最后的两个字段 department(学生所属的院校) 和 dean (这个院系的院长 )。一个学生的院长是谁,是取决于学生所在的院系,最后的两个字段存在依赖关系。所以进一步优化表结构:
department 表

student 表

将原本的学生表拆为院系表、学生表两张,学生表中则是只存储一个院系id,由院系表存储院系相关的所有数据。学生表中的每个非主键字段与其他非主键字段之间,都是相互独立的,之间不会再存在任何依赖性,所有的字段都依赖于主键。
(3)不满足3NF的影响:
会因字段传递依赖,导致数据冗余(同信息重复存)
更新异常(改一个值需动多条数据,易漏改)
删除异常(删数据可能误删或残留脏数据)
插入异常(新信息难单独插入)
让表结构难维护、业务流程易受牵连
5.三范式小结
1NF:确保原子性,表中每一个列数据都必须是不可再分的字段。
2NF:确保唯一性,每张表都只描述一种业务属性,一张表只描述一件事。
3NF:确保独立性,表中除主键外,每个字段之间不存在任何依赖,都是独立的。
经过三范式的设计优化后,整个库中的所有表结构,会显得更为优雅,灵活性也会更强。
6.巴斯-科德范式(BCNF)
(1)**核心问题:**3NF未约束联合主键字段间的依赖。若联合主键中某字段依赖另一字段,仍会导致冗余、更新异常。
(2)**示例:**这里我们可以通过联合主键,确定学生表中任何一个学生的信息,但是一条学生信息中的班主任(adviser),取决于学生所在的班级,因此班主任字段其实也依赖于班级字段。

如果联合主键中的一个字段依赖于另一个字段,会造成不小的问题,使得整张表的维护性变差,因此这里需要进一步调整结构:


原本的学生表则又被拆为了班级表、学生表两张,在学生表中只存储班级id,然后使用班级id和学生姓名两个字段作为联合主键。
注:第三范式只要求非主键字段之间,不能存在依赖关系,但没要求联合主键中的字段不能存在依赖,因此第三范式并未考虑完善,巴斯-科德范式修正的就是这点,是对第三范式的补充及完善。
7.第四范式(4NF)
(1)**核心问题:**表中存在多值依赖(一个字段值由多个字段共同决定,如用户权限依赖"用户+角色" ),导致冗余和操作异常。
(2)示例:

各字段含义:
user_name:用户名
role:角色信息
ROOT:超级管理员角色
ADMIN:管理员角色
USER:普通用户角色
permission:权限信息
*:超级管理员拥有的权限级别,*表示所有
BACKSTAGE:管理员拥有的权限级别,表示可操作后台
LOGIN:普通用户拥有的权限级别,表示可登录访问平台
一个用户可以拥有多个角色,同时一个角色可以拥有多个权限,所以此时无法单独根据用户名去确定权限值,权限值必须依赖用户、角色两个字段来决定,这种一个字段的值取决于多个字段才能确定的情况,就被称为多值依赖
需进一步将表格拆分为:
users 表

roles 表

permissions 表

users_roles 表

roles_permissions 表

将原本的用户角色权限表,拆分成了用户表、角色表、权限表、用户角色关系表、角色权限关系表。一方面用户表、角色表、权限表中都不会有数据冗余,第二方面无论是要删除亦或新增一个角色、权限时,都不会影响其他表。后面的两张关系表,主要是为了维护用户、角色、权限三者之间的关系。
8.第五范式
(1)规则: 建立在4NF
的基础上,进一步消除表中的连接依赖,直到表中的连接依赖都是主键所蕴含的。
(2)**实际价值:**解决"无损连接"理论问题,生产环境极少用到(场景罕见、难察觉 ),了解即可。
9.第六范式
(1)**概念:**域键范式,也被称之为终极范式,但目前也仅有学术机构在研究,在生产环境中实际的用途也不大
10.反范式
(1)**概念:**不遵循数据库范式设计的结构,称为反范式结构。
(2)优缺点:
优点
消除数据冗余,节省存储空间;
表结构清晰,简化 SQL 操作、减少出错。
缺点(范式级别过高时)
数据分散到多张表,联表查询需求暴增;
联表过多可能引发索引失效,严重拖慢业务系统性能。
(3)**设计意义:**因范式过高会导致性能问题,设计库表时无需 100% 遵循范式;当"破坏范式对业务的好处>坏处"时,主动采用反范式设计。
注:不以规则为绝对标准,业务优先:能支撑业务需求、带来实际价值的设计,就是好设计。
二、数据库范式设计总结
1.范式设计的整体认知
(1) **复杂度与代价:**范式级别越高,理解难度越大,为满足范式付出的设计代价(如拆分表数量、性能开销)也越大。
(2) **实际项目应用:**一般项目中,满足到第三范式(3NF)或巴斯 - 科德范式(BCNF) 即可,继续追求更高范式易因过度精细设计导致整体性能下降。
(3)**灵活权衡原则:**控制在第三范式级别,可平衡数据冗余与性能影响;若打破范式对业务更有利,也可违背范式设计。
2.库表结构设计的合理性对比
(1)**不合理设计的问题:**会造成数据冗余,浪费存储空间;不便于常规 SQL 操作(如插入、删除),甚至引发异常。
(2)**合理设计的好处:**节省空间(内存和磁盘);数据划分合理,数据库性能高且数据完整;结构便于维护和常规SQL操作
(3)**各范式递进关系:**呈包含关系,从第一范式(1NF)到域键范式(终极范式),级别越高约束越严格,如 1NF⊂2NF⊂3NF⊂BCNF⊂4NF⊂5NF⊂域键范式 。
(4)各范式概念:
1NF(第一范式):原子性,字段值不可再分。
2NF(第二范式):唯一性,字段依赖主键,每行数据描述同一业务属性。
3NF(第三范式):独立性,非主属性不传递依赖于主键。
BCNF(巴斯 - 科德范式):主键字段独立性,联合主键字段间无依赖性。
4NF(第四范式):多值依赖,表中一个字段值由多个字段决定。
5NF(第五范式):无连接依赖,表中字段数据间不存在连接依赖关系。
域键范式(终极范式):追求库表设计的终极完美范式,目前多处于学术研究阶段 。
三、MySQL数据库账户及授权
1.密码策略
(1)密码插件:
MySQL版本 | 默认密码插件 | 替换原因 |
---|---|---|
8.0+ | caching_sha2_password | mysql_native_password,解决SHAI算法安全性问题(易被破解) |
5.7及以下 | mysql_native_password | 依赖SHAI算法,已被NIST建议弃用 |
关键差异: caching_sha2_password 更安全, mysql_native_password 验证速度快,但算法弱
(2)查看数据库当前密码策略的语句:show variables like '%password%';(查看所有密码相关变量)

(从上往下 )表中每一行的意思:
是否自动生成RSA密钥对文件
哈希轮数,数值越大安全性越强
RSA 私钥文件
RSA 公钥文件
MySQL密码过期时间,单位为天
超时断开
随机密码长度
是否支持代理用户控制认证插件
不允许用户使用最近n次使用过的密码
修改密码时是否需要提供当前用户使用的密码,OFF不需要,ON需要
不允许用户使用最近n天内使用过的密码
该变量通常为空,它可能用于特定的报告或审计目的
(3)**查看密码设置策略:**show variables like 'validate_password%';
注:若显示为空,则表示未装插件,输入安装插件语句即可:Iinstall component 'file://component_validate_password';

(从上往下 )表中每一行的意思:
用于控制密码修改时字符变化比例的要求
能将密码设置成当前用户名
插件用于验证密码强度的字典文件路径,默认为空
密码最小长度,默认为8,有最小值为4的限制
密码至少要包含的小写字母和大写字母的个数
密码至少要包含的数字个数
密码强度检查等级
密码必须包含的特殊字符个数
(4)密码强度检查等级解释(validate_password.policy) :
等级 | 检查对象 |
---|---|
0 或 low | 检查长度6 |
1 或 medium | 检查长度、数字、大小写、特殊字符 |
2 或 strong | 检查长度、数字、大小写、特殊字符、字典文件 |
(5)设置密码强度检查的语句:
设置密码验证强度检查策略:set global validate_password.policy=等级强度;
设置至少要包含大/小写字母的个数:set global validate_password.mixed_case_count=个数;
设置至少要包含数字的个数:set global validate_password.number_count=个数;
设置至少包含特殊字符个数:set global validate_password.special_char_count=个数;
设置密码长度:set global validate_password.length=长度值;
修改后,可刷新权限,使其生效:flush privileges;
(6)修改密码的语句:
先查看 root 用户信息:select user, host, plugin from mysql.user;
再修改其密码:alter user 'root'@'来源地址' identified by '新密码';(来源地址---本地主机为localhost,远程主机为%)
最后刷新权限即可
2.登录账户管理
(1)管理原则: MySQL8遵循**"** 先创建账户,再赋予权限**"**的流程,清晰分离账户创建与权限配置步骤
(2)关键操作命令:
操作目标 | SQL命令 | 说明 |
---|---|---|
查看当前用户信息 | select user(); | 快速获取当前登录用户名 |
进入系统数据库 | use mysql; | 切换到存储用户数据的库 |
查看数据库表 | show tables; | 确认 user 表存在 |
查看用户表结构 | desc user; | 了解 user 表字段设计 |
查询用户核心信息 | select user,host,authentication_string from user; | 提取账号、允许登录主机、加密密码 |
3.新建登录账户
(1)**新建账户的语句:**create user '用户名'@'来源地址' identified by '密码';
注:登录主机为 localhost(本地登录) 或 %(远程登录)

退出当前账户,登录新建的账户,看是否能成功进入(只能查看有限库):

4.账户授权
(1)账户权限管理原则:
最小化赋权:生产环境仅授予必要权限(如 select ),避免高危操作( update / insert )
分离角色:区分管理账号( root )与应用账号(业务用户)
定期清理:删除/回收闲置账户权限
(2)常见的用户权限:


(3)**查看权限的语句:**show grants;(查看当前用户) show grants for '用户名'@'来源地址';(查看其他账户权限)

上例显示 haha 账户只有 usage 默认权限,即连接登录权限
(4)**赋予账户权限的语句:**grant 权限列表 on 数据库名.表名 to '用户名'@'来源地址' ;

赋予 haha 账户查询mysql库的权限
查看 user 表的权限信息:

登录被赋予权限的账户,测试一下:

(5)**新建远程账户(指定网段):**create user 'test1'@'网段' identified by '密码';


(6)新建高权限账户(含赋权能力):

但是,all 所有权限中不包含给账户赋权的权限 grant:

给 haha 账户赋予给别的账户赋权的权限:

若赋权不成功则先给 root 账户增加 system_user 权限

5.回收权限
(1)**作用:**取消用户已授权的数据库操作权限,细化权限管理
(2)**语句:**revoke 权限列表/all on 库名.表名 from '用户名'@'来源地址';
回收 select 权限

回收所有权限

6.删除账户
(1)**作用:**彻底清除MySQL用户,连带其权限配置,清理无用账户
(2)**语句:**drop user '用户名'@'来源地址'; drop user 用户名(来源地址为%,可不写来源地址)
