【MySQL 设计师视角 数据库结构设计】

数据库结构设计

设计流程一览:

业务分析---------->逻辑设计--------------->物理设计---------->对像命名

业务分析

我们这里以慕课网免费课前端为项目,进行数据库的结构设计,并非实际慕课网的数据库结构。
首先来看慕课网前端的页面,可以进行项目的需求总结:
在这里插入图片描述
可以先罗列出对象及对象的属性:

  • 课程的属性:{主标题,副标题,方向,分类,难度,最新最热,时长,简介,人数,需知,收获,讲师名,讲师职位,课程图片,综合评分,内容实用,简洁易懂,逻辑清晰}
  • 课程列表的属性:{章名,小节名,说明,小节时长,章节URL,视频格式}
  • 讲师的属性:{}讲师昵称,说明,性别,省,市,职位,说明,经验,积分,关注,人数,粉丝人数}
  • 问答评论属性:{类型,标题,内容,关联章节,浏览量,发布时间,用户昵称}
  • 笔记的属性:{用户昵称,关联章节,笔记标题,笔记内容,发布时间}
  • 用户的属性:(用户昵称,密码,说明,性别,省,市,职位,说明,经验,积分,关注人数,粉丝人数}
  • ◆评价的属性:(用户,课程主标题,内容,综合评分,内容实用,简洁易懂,逻辑清晰,发布时间}

逻辑设计

宽表模式

这里我们拿课程表来理解,宽表顾名思义就是将一个对象的所有属性等不同的内容全都放在一张表中存储。在这里插入图片描述
使用宽表存储数据:

  • 会发现相同的数据出现多次,造成数据冗余,会占用大量的存储空间。
  • 数据更新异常:修改一行中某一列的值时,同时又修改了多行数据
    在这里插入图片描述
    如我只想修改第一行的讲师职位信息,则用下面的语句,如果不加主键信息,则会修改四行,如果加了,则会发现信息不一致的问题——同个讲师在不同课程的职位不同。
  • 数据插入异常:部分数据由于缺失主键无法写入表中
    在这里插入图片描述
    如果我们想在方向这一列添加一个“后端开发”的方向,则会用上面那一句SQL,但是表中没有匹配的课程主标题,则主键为空,这也违反了主键非空且唯一的约束,所以这个“后端开发”无法写入表中。
  • 数据删除异常:删除某一数据时不得不删除其他数据
    在这里插入图片描述
    想要删除数据库这一方向,则用
delete from ‘课程表’ where 方向=‘数据库’

但同时我们也删除了方向为数据库的所有课程,这就违反了我们的需求。

  • 适用场景:配合列存储的报表应用。

设计范式

第一范式

要求我们:表的所有字段都是不可再分的
如下图,联系方式这一字段还有手机,固话,邮箱这三个字段,所以违反了第一范式 在这里插入图片描述
我们可以修改成这样,这就符合了第一范式的设计规则: 在这里插入图片描述

第二范式

要求我们:表中必须存在业务主键,且非业务主键全部依赖于业务主键(若是组合业务主键,非业务主键也必须依赖于全部组合列)
在这里插入图片描述
我们可以看到,这张表的业务主键为用户,章节和标题组合而成的复合主键,那么其他非业务主键必须依赖于这三列,但是用户积分这一列只依赖于用户这一列,所以这违反了第二范式的要求
在这里插入图片描述
我们可以将不存在依赖关系的列全部提取出来,单独放到一个表中,这就维护了第二范式的规则,同时我们也发现,如果业务主键只有一个列,那么这个表天生符合第二范式要求的

第三范式

要求我们:表中的非主键列之间不能互相依赖
在这里插入图片描述
可以看到,上面这张表中,讲师职位列与讲师名是相互依赖的,与主键列无依赖关系,所以我们单独将这两列提取出来,形成一个单独的表
在这里插入图片描述

面向对象设计

从课程对象来看:
在这里插入图片描述
从课程列表对象来看:
在这里插入图片描述
从用户对象,问答评论对象来看:
在这里插入图片描述
从课程评价上看:
在这里插入图片描述
以上就是对慕课网前端的所有表结构设计,里面运用了反范式化设计,使得查询性能更优。

物理设计

常用的MySQL存储引擎

对于MySQL数据库来说,首先要选择存储引擎,而存储引擎又决定了数据的存储结构,我们来看一下可供选择的存储引擎有哪些

在这里插入图片描述

MYISAM与INNODB的区别

1.是否支持行级锁 : MyISAM 只有表级锁(table-level locking),而InnoDB 支持行级锁(row-level locking)和表级锁,默认为行级锁。

2.是否支持事务和崩溃后的安全恢复: MyISAM 强调的是性能,每次查询具有原子性,其执行速度比InnoDB类型更快,但是不提供事务支持。但是InnoDB 提供事务支持事务,外部键等高级数据库功能。 具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。

3.是否支持外键(表的外键是另一表的主键, 外键可以有重复的, 可以是空值,用于关联查询中): MyISAM不支持,而InnoDB支持。

4.是否支持MVCC :仅 InnoDB 支持。应对高并发事务, MVCC比单纯的加锁更高效;MVCC只在 READ COMMITTED 和 REPEATABLE READ 两个隔离级别下工作;MVCC可以使用 乐观(optimistic)锁 和 悲观(pessimistic)锁来实现;各数据库中MVCC实现并不统一。

INNODB存储引擎

特点:

  • 事务型存储引擎支持ACID
  • 数据按主键聚集存储(INNODB表中的主键是一种聚集索引主键,每一个非主键索引的叶子节点所指向的都是数据行中的主键,而不是数据物理存储位置,因此主键的大小影响到查找的性能,建议使用自增ID作为表的主键)
  • 支持行级锁和MVCC(行级锁,也就是你需要修改哪行,就锁定哪行,InnoDB 中的行锁是通过给索引项加锁实现的,如果没有索引,InnoDB 会通过隐藏的聚集索引来对记录加锁。也就是说:如果不通过索引条件检索数据,那么InnoDB将对表中所有数据加锁,实际效果跟MYISAM中的表锁一样)
  • 支持Btree和自适应哈希索引
  • 支持全文索引和空间索引(在MySQL5.7版本之后支持全文索引和空间索引,在5.7版本之前,只能使用MYISAM的表才能全文索引或空间索引)

MACC在INNODB中的实现

MVCC即多版本并发控制:MVCC使得大部分支持行锁的事务引擎,不再单纯的使用行锁来进行数据库的并发控制,取而代之的是把数据库的行锁与行的多个版本结合起来,只需要很小的开销,就可以实现非锁定读,从而大大提高数据库系统的并发性能。

在InnoDB中,会在每行数据后添加两个额外的隐藏的值来实现MVCC,这两个值一个记录这行数据何时被创建,另外一个记录这行数据何时过期(或者被删除)。 在实际操作中,存储的并不是时间,而是事务的版本号,每开启一个新事务,事务的版本号就会递增。 事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行的版本号进行比较,在可重读Repeatable reads事务隔离级别下:
在这里插入图片描述

  • INSERT时,会为新插入的每一行保存当前系统的版本号作为行版本号;
  • DELETE 时,会为删除的每一行保存当前系统的版本号作为删除标识;
  • UPDATE时,会为更新的一行保存当前系统版本号为行版本号,同时会保存当前系统版本号作为原来的行的删除标识

通过MVCC,虽然每行记录都需要额外的存储空间,更多的行检查工作以及一些额外的维护工作,但可以减少锁的使用,大多数读操作都不用加锁,读数据操作很简单,性能很好,并且也能保证只会读取到符合标准的行,也只锁住必要行。
推荐阅读:mysql-innodb-mvcc
MySQL INNODB MVCC深度分析
MVCC

快照读与当前读

在RR级别中,通过MVCC机制,虽然让数据变得可重复读,但我们读到的数据可能是历史数据,是不及时的数据,不是数据库当前的数据!这在一些对于数据的时效特别敏感的业务中,就很可能出问题。

对于这种读取历史数据的方式,我们叫它快照读 (snapshot read),而读取数据库当前版本数据的方式,叫当前读 (current read)

快照读:

  • select * from table…;

当前读:这个状态下会为该行加锁,其他事务就需要等待该事务提交后才可对该行操作

  • select * from table where ? lock in share mode;
  • select * from table where ? for update;
  • insert;
  • update ;
  • delete;

在RR隔离级别的普通查询语句中,INNODB会默认执行快照读,所以当你如果在进行增、删、改完成之后,再进行SELECT操作,则此时读取到的是最新版本的数据。如果是在增、删、改之前进行了快照读SELECT操作,在增、删、改之后继续快照读SELECT操作,则读到的就是旧版本数据。

Session A :
select * from table where id = 1;  // id = 1 xx = 'a'
Session B :
update table set xx = 'b' where id =1; // id = 1 xx = 'b'
Session A:
select * from table where id = 1 lock in share mode; // 读到新数据 xx = 'b'
select * from table where id = 1;  // 读到旧数据 xx = 'a'

Session B :
update table set xx = 'b' where id =1; // id = 1 xx = 'b'
Session A :
select * from table where id = 1;  // id = 1 xx = 'b'	
select * from table where id = 1 lock in share mode; // 同上

根据INNODB优化表结构

在这里插入图片描述
课程表中:添加课程ID作为表的业务主键,其为自增ID,课程表的逻辑存储顺序则按照自增ID来存储的,可以保证后加入的数据一定是排在表的末尾的,不会破坏表的逻辑存储顺序,同时为了保证主标题的唯一性,可以在主标题这一列建立唯一索引(具有唯一索引的列不允许具有相同的行),除此之外,为了能关联其他表,将方向名称更改为方向表的业务主键方向ID,同样,分类表,难度表和用户表也是如此,利用业务主键替换业务的这种方式有利有弊,利是可以保持数据的一致性,比如更新讲师表中的讲师昵称,由于关联查询同时也更新了课程表中的讲师昵称,缺点是需要课程表关联用户表,增加了数据冗余,所以具体情况看业务需求。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
同样,在其他表中,都设置一个自增ID作为业务主键,并且将关联表的列设置为关联表的业务主键ID。

数据类型

整数类型

在这里插入图片描述
一个字节占8个比特位,所以tinyint类型在有符号中取值范围为-128~127,无符号为0-255,所以在选择整数类型时,要选择符合的类型,才能达到节省存储空间的效果,比如存储两位整数应用tinyint类型。

实数类型

在这里插入图片描述
在这里插入图片描述
DECIMAL(a,b):整数部分加小数部分总长度为a,小数部分长度为b
执行以下代码:

create database test;
use test;
create table t(d1 double,d2 decimal(10,3));
insert into t values (11.1,11.1),(22.2,22.2);
select sum(d1),sum(d2) from t;

在这里插入图片描述
所以处理财务报表之类的数据时,推荐使用DECIMAL数据类型

时间类型

在这里插入图片描述
TIME:time类型数据能存储一段时间,所以范围才会如此大,而存储空间为什么是3到6 个字节呢?这与它的微秒值有关,如下图
在这里插入图片描述
微秒值每增加两位增加一个字节,最多可以有6位,所以最多加3个字节
在这里插入图片描述
YEAR:YEAR类型数据只占用一个字节,用来存储年份数据类型,所以当存储1901到2055年之间年份时,比用整数类型或字符串类型要节省空间。

TIMESTAMP:可以看到不同时区的时间,存储时间范围没有DATETIME广,以下通过一个例子演示:

CREATE TABLE t_timestamp(dt TIMESTAMP);
INSERT INTO t_timestamp SELECT NOW();//这里是东8区
SELECT * FROM t_timestamp;
SET time_zone='+10:00';//改为东10区
SELECT * FROM t_timestamp;

东8区的时间:
在这里插入图片描述
东10区的时间:
在这里插入图片描述

字符串类型

在这里插入图片描述
Char(M):这个类型只要定义了M个字符,无论是否存储了M个字符,都会占用M个字符的存储空间;
VarChar(M):这个类型是也会定义宽度M,字符集长度不能超过M,但在实际中只会占用实际需要的存储空间,需要注意的是,这里不能超过65535个字节,是M和实际字符集占用字节的乘积;

如何为列选择合适的数据类型

  • 优先选择符合存储数据需求的最小数据类型(把字符串类型转换成整数类型存储,如IP地址转换成整数,)

在这里插入图片描述
上图IP地址以字符串存储需15个字节,转成整数类型只需4个字节;

  • 谨慎使用ENUM,TEXT字符串类型
  • 财务相关的数据类型必须使用DECIMAL数据类型

为项目的表选择合适的数据类型

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

为数据库对像命名

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱技术的小小林

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值