49.mysql优化-表结构之数据库设计三大范式

202 阅读6分钟

说到表结构的设计,必然绕不开数据库设计三大范式,先从据库设计三大范式开始讲起。

1.原子性:每列不可拆分即字段不可再分

如:中国台湾 中国河南 可以拆分为 中国 台湾 和中国 河南。违反了原子性。

违反第一范式原子性会带来的问题:无法做等值查询。

如果想要查询省份为河南的,是没法做到的。

案例

以储物业务场景为例,1次储物操作,可以有多个取物人的手机号。

当存在多个取物人手机号时使用储物表storage的1个列去存储,使用[ , ]分割。

但是在一些场景下,发现这种设计是无法满足业务需求的,比如等值查询并分页。

解决办法是做增加1个储物取物手机号关联表,储物和储物取物人手机号是一对多的关系。

2.唯一性 + 有主键,非主键字段依赖主键

第二范式有2个要求:

1.唯一性:一个表只说明一个事物,确保一个表只做一件事。

例如:学生表 即保存了 姓名 年龄 性别 爱好 喜欢吃什么 银行卡号 学生卡号 身份证号

这张学生表万能,就违反了唯一性。

2.建立在第一范式的基础之上,要求所有非主键字段完全依赖主键,不要产生部分依赖。

表中的每一列都要与主键直接相关,而不是间接相关。

例如:订单表:订单编号、商品编号、订购日期、价格等字段

"订单编号"为主键,"商品编号"和主键列没有直接的关系,即"产品编号"列不依赖于主键列,应删除该列。

单独建立1个订单标号和产品编号的关系表。

image.png

这个表同时违反了了第一范式和第二范式,其中籍贯是可以在拆分的,课程信息和是成绩信息间接依赖于学生。

成绩是依赖课程和学生的。

所以可以建立以下表

1.学生信息表:学生id姓名、性别、省份、城市、学分

2.课程表:课程id、课程名称

3.学生成绩表:学生id、课程id、成绩

3.非主键字段不能相互依赖

在满足2的情况下消除表的传递依赖。目的是消除传递依赖,避免字段冗余。

即通过A 可以推导出 B 通过B可以推导出C 通过A也能推出C 这样会造成字段冗余和空间浪费以及级联更新。

例如:订单表(订单编号,订购日期,顾客id,顾客姓名,……),初看该表没有问题,满足第二范式,每列都和主键列"订单编号"相关。 再细看你会发现"顾客姓名"和"顾客id"相关,"顾客id"和"订单编号"又相关,最后经过传递依赖,"顾客姓名"也和"订单编号"相关。为了满足第三范式,应去掉"顾客姓名"列,放入客户表中。

如 id 数量 单价 总价

通过id 可以知道 数量 单价 通过 数量单价可以得到 总价

数量和单价变了,总价必须要变。

每列都与主键有直接关系,不存在传递依赖。

image.png

以上表违反了第一范式和第三范式,非主键字段也完全依赖于主键字段。

但是,院系电话字段,其实是依赖院系字段的。

也就是说,院系电话字段是非主键值,而依赖了另一个非主键值-院系。所以就不符合第三范式。

综合案例

建立一个描述学校教务的数据库,该数据库有1个学生表student,包括学生的学号:student_no,学生所在系:student_dept,系主任姓名:dept_director_name,课程号:course_no和成绩:student_grade。

首先这是1张万能表,违反了数据库设计的第二范式唯一性:一个表只说明一个事物,确保一个表只做一件事。

所有与学生相关不相关的信息都存在了这个表里,这就导致了学生表的学生信息与其它不相关的信息耦合在了一起,会引起一连串的问题。

其次造成了数据冗余:违反第三范式:每一个学生对应的系的系主任姓名、所属系的信息重复出现。

导致了以下问题 更新异常:比如:某个系更换系主任后,必须修改与该系学生有关的每一个条记录 插入异常:比如:一个系刚成立,暂时没有学生,则无法把这个系以及系主任的信息存入数据库; 删除异常:比如:某个系的学生全部毕业了,则在删除该系学生信息的同时,这个系及系主任的信息也删除了。

分析:学生和系是1对1的关系,系和系主任也是1对1的关系,因此只要维护好这个1对1的关系即可。

解决方法 1.在学生表维护系主任的id和所属系的id。 2.建立1个中间表专门维护学生和系的关系。 好处:解决了更新异常的问题。

所以表结构可以拆分为以下几个表 1.学生表(student_no) 2.系表(dept_no) 3.学生-系中间表(student_no,dept_no) 4.课程表(course_no) 5.学生-课程表(student_no,course_no)

总结

原子性:不可拆分

唯一性:有主键,一个表说明1个事情。

不冗余:消除依赖传递,避免字段冗余。

反三范式

数据库只是数据库表设计时的理论依据,最终的目的是为了满足客户的需求,:实际开发时,通过添加冗余字段满足一些用户的特殊要求。有时候会选择用数据库表的冗余来换取执行速度,因为在查询过程中,多张表的连接会降低查询的效率。

范式化设计的优点和缺点

优点:可以减少数据冗余,数据表体积小更新快,范式化的更新操作比反范式化更快,范式化的表通常比反范式化更小。

缺点:对于查询需要对多个表,会关联多个表,在应用中,进行表关联的成本是很高,进行索引优化更难

反范式化设计的优缺点

优点:可以减少表的关联,可以对查询更好的进行索引优化

缺点:表结构存在数据冗余和数据维护异常,对数据的修改需要更多资源。

因此在设计数据库结构的时候要将反范式化和范式化结合起来