数据库基础知识三

  • 1. 存储引擎
  • 1.1介绍
  • 1.2 介绍常见的存储引擎
  • 1.2.1 MyISAM存储引擎
  • 1.2.2 InnoDB存储引擎
  • 1.2.3 MEMORY存储引擎
  • 2. 事务(重要)
  • 2.1 事务的基本概念
  • 2.2 事务的4个基本特性
  • 2.3 事务隔离级别
  • 3. 索引
  • 3.1 索引的基本概念
  • 3.2 索引的失效
  • 3.3 索引的分类
  • 4. 视图(view)
  • 5. DBA常用的两个命令
  • 6. 数据库设计三范式
  • 6.1 第一范式
  • 6.2 第二范式
  • 6.3 第三范式


1. 存储引擎

1.1介绍

存储引擎:是一个表存储/组织数据的方式。不同的存储引擎,表存储的方式不同。数据库中的各表在创建时均被指定的存储引擎来处理。这是MySQL中特有的术语,Oracle中不叫该名字。

  • 服务器可用的引擎依赖于以下因素:①MySQL的版本;②服务器在开发时如何被配置;③启动选项
  • 用SHOW ENGINES \G;命令查看当前服务器中都有哪些存储引擎可用
  • SHOW CREATE TABLE T_STUDENT;可以查看建表的具体操作;
  • MySQL默认的存储引擎是:InnoDB; 默认的字符编码方式是:utf-8
  • MySQL支持9大存储引擎,当前8.0.29支持8个,版本不同支持情况不同

在建表的时候可以再最后小括号")"的右边使用 ENGINE=xxx来指定存储引擎

create table t_class(
	classno int primary key,
	classname varchar(32)
) engine = InnoDB default charset = gbk; -- 指定默认的额存储引擎和字符编码方式

1.2 介绍常见的存储引擎

1.2.1 MyISAM存储引擎

它使用三个文件表示每个表:

  • 格式文件:存储表结构的定义(mytable.frm)
  • 数据文件:存储表行的内容(mytable.MYD)
  • 索引文件:存储表上的索引(mytable.MYI)

优点:可被转换为压缩、只读表来节省空间
缺点:不支持事务,安全性低

1.2.2 InnoDB存储引擎

这是MySQL默认的存储引擎,同时也是一个重量级的存储引擎。InnoDB支持事务,支持数据库崩溃后的自动恢复机制。InnoDB最主要的特点是支持事务,以保证数据的安全。

它管理的表具有下列主要特征:

  • 每个InnoDB表在数据库目录中以.frm格式的文件表示
  • InnoDB表空间tablespace被用于存储表的内容(表空间是一个逻辑名称,表空间存储数据+索引)
  • 提供一组用来记录事务性活动的日志文件
  • 用COMMIT,SAVEPOINT以及rollback支持事务处理
  • 提供ACID兼容
  • 在MySQL服务器崩溃后提供自动恢复
  • 多版本(MVCC)和行级锁定
  • 支持外键以及引用的完整性,包括级联删除和更新

InnoDB缺点:因为安全,所以效率不是很高,并且也不能压缩,不能转换为只读,不能很好地节省空间

1.2.3 MEMORY存储引擎

使用MEMORY存储引擎的表,其数据存储在内存中,且行的长度固定,这两个特点使得MEMORY存储引擎非常的快。
MEMORY存储引擎管理的表具有以下特征:

  • 在数据库目录内,每个表均以.frm格式的文件表示
  • 表数据及索引都被存储在内存中(目的就是查询快)
  • 表级锁机制
  • 不能包含TEXT或BLOB字段。

MEMORY存储引擎以前被称为HEAP引擎。
优点:查询效率是最高的
缺点:不安全,关机之后数据消失。因为数据和索引都是在内存当中。

2. 事务(重要)

2.1 事务的基本概念

  1. 什么是事务?

一个事务就是一个完整的业务逻辑,是一个最小的工作单元,不可再分。
什么是一个完整的业务逻辑:
假设转账,从A账户向B账户转1000,将A账户的钱减去1000(update语句),同时将B的账户的钱加上1000(update语句),这就是一个完整的业务逻辑。
以上的操作是一个最小的工作单元,要么同时成功,要么同时失败,不可再分。

  1. 只有DML(insert、delete、update)语句才和事务有关系,其他语句和事务无关,因为只有以上的三个语句是对数据库表中数据进行增、删、改的。只要操作涉及到增、删、改,就需要考虑安全问题,数据安全是第一位的!
  2. 对事务的理解:

假设所有的业务,只要一条DML语句就能完成,就没必要存在事务机制。正是因为做某件事的时候,需要多条DML 语句共同联合完成,所以需要事务的存在。说到底,一个事务其实就是多条DML语句同时成功,或者同时失败。

  1. 事务是怎么做到多条DML语句同时成功或同时失败的?

InnoDB存储引擎:提供一组用来记录事务性活动的日志文件
事务开始:insert-insert-delete-delete-update-update 事务结束!
在事务的执行过程中,每一条DML的操作都会记录到‘事务性活动的日志文件’中,我们可以提交事务,也可以回滚事务。
提交事务:清空事务性活动的日志文件,将数据全部彻底持久化到数据库表中。提交事务标志着事务是一种全部成功的结束。
回滚事务:将之前所有的DML操作全部撤销,并且清空事务性活动的日志文件。回滚事务标志着,事务是一种全部失败的结束。

  1. 怎么提交事务?怎么回滚事务?
    事务:transaction
    提交事务:commit; 语句
    回滚事务:rollback; 语句(回滚永远都只能回滚到上一次的提交点)
    MySQL中默认情况下是自动提交事务的,即每执行一条DML语句就提交一次。
    将MySQL的自动提交关闭:start transaction;
回滚事务:
drop table t_vip if exists;
create table t_vip(
	id int(5) primary key auto_increment,
	name varchar(32)
);
start transaction;
insert into t_vip(name) values ('zhangsan');
insert into t_vip(name) values ('zhangsan');
insert into t_vip(name) values ('zhangsan');
select * from t_vip; --此时可以查到t_vip中有三条数据
rollback; 
select * from t_vip; --此时可以查到t_vip中没有数据

提交事务:
drop table t_vip if exists;
create table t_vip(
	id int(5) primary key auto_increment,
	name varchar(32)
);
start transaction;
insert into t_vip(name) values ('zhangsan');
insert into t_vip(name) values ('zhangsan');
insert into t_vip(name) values ('zhangsan');
commit; --提交事务
select * from t_vip; --此时可以查到t_vip中有三条数据
rollback; 
select * from t_vip; --此时依然可以查到t_vip中没有数据

2.2 事务的4个基本特性

  1. 原子性(Atomicity)
    说明事务是最小的工作单元,不可再分。整个事务的所有操作,必须作为一个单元全部完成(或全部取消)
  2. 一致性(Consistency)
    在事务开始之前与结束之后,数据库都保持一致状态。这就需要一个事务的所有操作必须同时成功,或同时失败,以保证数据的一致性。
  3. 隔离性
    一个事务不会影响其他事物的运行。A事务和B事务之间具有一定的隔离,A在操作一张表时B也在操作这张表会怎样?
  4. 持久性
    在事务完成以后,该事务对数据库所做的更改将永久地保存在数据库中,并不会被回滚。

2.3 事务隔离级别

  1. 读未提交:read uncommitted(最低的隔离级别)《没有提交就读到了》
    这种级别,事务A可以读取到事务B未提交的数据。
    缺点:脏读现象(dirty read),我们称读到了脏数据
    这种隔离级别一般都是理论上的,大多数的数据库隔离级别都是二级起步。
  2. 读已提交:read committed《提交之后才能读到》
    事务A只能读取到事务B提交之后的数据。
    优点:解决了脏读现象。
    缺点:不可重复读取数据。假如在事务开启后,第一次读到的数据是3条,当前事务还没有结束,可能第二次读到的数据是4条,3不等于4,称为不可重复读取。
    这种隔离级别是比较真实的数据,每一次读到的数据是绝对真实的。是Oracle数据库中默认的隔离级别。
  3. 可重复读:repeatable read《提交之后也读不到,永远读到的都是刚开启事务时的数据》
    事务A开启后,不管过多久,每一次在事务A中读取到的数据都是一致的。即使事务B将数据已经修改并且提交,事务A读取到的数据库的数据还是没有发生变化,这就是可重复读。
    优点:解决了不可重复读取数据的问题。
    缺点:可能会出现幻影读。每一次读到的数据都是幻象,不够真实。
    MySQL中默认的事务隔离级别就是3级。
  4. 序列化/串行化:serializable(最高的隔离级别)
    这是最高隔离级别,效率最低,解决了所有的问题。
    这种隔离级别表示事务是排队执行,不能并发!
    类似于synchronized,线程同步(事务同步),每一次读取到的数据都是最真实的,并且效率最低。
select @@transaction_isolation; --查看数据库当前隔离级别(MySQL8以后)
select @@tx_isolation;--查看数据库当前隔离级别(MySQL8以前)
set global transaction isolation level read uncommitted;-- 设置全局事务的隔离级别,设置完退出重新进入才生效

3. 索引

3.1 索引的基本概念

索引是在数据库表的字段上添加的,是为了提高查询效率存在的一种机制。一张表的任何一个字段都可以添加索引,也可以多个字段联合起来添加索引,索引相当于一本书的目录,是为了缩小扫描范围而存在的一种机制。

MySQL的查询方式主要有两种:①全表扫描;②根据索引检索。

注意:在实际中,汉语字典的目录是排序的,因为只有排序了才有区间的说法,缩小扫描范围就是扫描某个区间。在MySQL中的索引也是需要排序的,并且这个排序和TreeSet数据结构相同。TreeSet(TreeMap)底层是一个自平衡的二叉树!在MySQL中索引是一个B-Tree(Binary)数据结构,遵循左小右大原则存放,采用中序遍历方式遍历数据。

索引的实现原理:

Opengauss mysql兼容性下创建序列_存储引擎


NOTE:

  • 在任何数据库中主键上都会自动添加索引对象,在MySQL中,一个字段上如果有unique约束时,也会自动创建索引。
  • 在任何数据库当中,任何一张表的任何一条记录在硬盘上都有一个硬盘的物理存储编号。
  • 在MySQL中,索引是一个单独的对象,不同的存储引擎以不同的形式存在,在MyISAM存储引擎中,索引存储在一个.MYI文件中。在InnoDB存储引擎中,索引存储在一个逻辑名称叫做tablespace中。在MEMORY存储引擎中索引存储在内存当中。不管索引存储在哪里,索引在MySQL中都是以一个B-Tree树的形式存在。

创建索引:

create index emp_ename_index on emp(ename); -- 给emp的ename字段添加索引,起名emp_ename_index

删除索引:

drop index emp emp_ename_index on emp; --将emp表上的emp_ename_index索引对象删除

在MySQL中,如何查看一个SQL语句是否使用了索引进行检索?

explain select * from emp;

查看其中type的结果:ALL=未使用索引;ref=使用索引,也可以从扫描的行数看到。

使用:

Opengauss mysql兼容性下创建序列_oracle_02


未使用:

Opengauss mysql兼容性下创建序列_mysql_03

3.2 索引的失效

很多情况下,索引会失效,例如

  1. select * from emp where ename like ‘%T’; 此时,即使ename添加了索引,也不会使用索引,因为模糊匹配以“%”开始。所以尽量避免模糊查询时以“%”开头,这是一种优化策略。
  2. 使用or的时候会失效。如果使用or那么要求or两边的条件字段都要有索引,才会使用索引,如果其中任何一个字段没有索引,那么另一个字段上的索引也会失效。此时可以使用union替代or。
  3. 使用复合索引的时候,没有使用左侧的列查找时,索引会失效。
    复合索引:两个或多个字段联合起来添加一个索引,叫做复合索引。
create index emp_job_sal_index on emp(job,sal);
explain select * from emp where job = 'Manager'; --此时索引可以使用
explain select * from emp where sal = 800; -- 此时索引失效
  1. 在where当中索引列参加了运算,索引失效
create index emp_sal_index on emp(sal);
explain select * from emp where sal + 1 = 800; -- 此时索引失效
  1. 在where中索引使用了函数
explain select * from emp where lower(ename) = 'smith';

3.3 索引的分类

索引是各种数据库进行优化的重要手段。优化的时候优先考虑的因素就是索引。索引在数据库当中分了很多类:

  • 单一索引:一个字段上添加索引
  • 复合索引:两个或两个以上的字段添加索引
  • 主键索引:主键字段上添加索引
  • 唯一性索引:具有unique约束的字段上添加索引

  • 注意:唯一性比较弱的字段上添加索引用处不大。

4. 视图(view)

视图:站在不同的角度去看待同一份数据。

表复制(操作复制后的表dept2数据,原表数据不会被改变):
create dept2 as select * from dept;
创建视图对象(操作视图对象的表emp_view1数据,原表数据会被改变):
create view emp_view1 as select * from emp;
删除视图对象:
drop view emp_view1;
注意:只有DQL语句才能以view的形式创建,即
create view view_name as 这里的语句必须是DQL语句
但是视图对象完成后,可以对视图对象进行增删改查等操作。

视图的作用:
我们可以面向视图对象进行增删改查,对视图对象的增删改查,会导致原表被操作。
假设有一条非常复杂的SQL语句,而这条语句需要在不同的地方反复使用,每一次使用这个SQL语句的时候都需要重新编写,就会很长很麻烦,此时,我们可以把这条复杂的语句以视图对象的形式创建,在需要编写这条SQL语句的位置直接使用视图对象,可以大大简化开发,并且利于后期的维护,因为修改的时候也只需要修改一个位置就行,只需要修改属兔对象所映射的SQL语句。

我们以后面向视图开发的时候,使用视图时可以像使用table一样。可以对视图进行增删改查(CRUD:create,retrieve(查,检索),update,delete)等操作。视图不是存在内存当中,而是存在硬盘上,不会消失。

5. DBA常用的两个命令

导出:

导出整个数据库:
在windows的cmd窗口中执行(不要登录MySQL):
mysqldump world > D:\test.sql -u root -p123
导出指定的某张表:
mysqldump world emp> D:\test.sql -u root -p123

导入:

先登录MySQL后执行下面的命令:
1.创建数据库:create databases world;
2.使用数据库:use world;
 - 然后初始化数据库: source  D:\test.sql

6. 数据库设计三范式

数据库设计范式指的就是数据库表的设计依据,教我们更好的进行数据库表的设计。
三范式内容:

  • 第一范式:要求任何一张表必须有主键,每一个字段都具有原子性,不可再分
  • 第二范式:建立在第一范式的基础之上,要求每个非主键字段都要完全依赖主键,不要产生部分依赖。
  • 第三范式:建立在第二范式的基础之上,要求每个非主键字段都要直接依赖主键,不要产生传递依赖。

设计数据库表的时候,按照以上的范式进行,可以避免表中数据的冗余,空间的浪费。

6.1 第一范式

第一范式是最核心,最重要的范式,所有表的设计都需要满足。
例如:

学生编号

学生姓名

联系方式

1001

张三

zs@email.com,13500000000

1002

李四

ls@email.com,15899999999

1001

王五

ww@email.com,18988888888

上面的表就不满足第一范式。没有主键,联系方式不具有原子性,还可以再分。修改为下面的表即可满足:

学生编号(pk)

学生姓名

邮箱

联系电话

1001

张三

zs@email.com

13500000000

1002

李四

ls@email.com

15899999999

1003

王五

ww@email.com

18988888888

6.2 第二范式

多对多,三张表,关系表两个外键!!!
第二范式建立在第一范式的基础之上,要求每个非主键字段都要完全依赖主键,不要产生部分依赖。

学生编号

学生姓名

教师编号

教师姓名

1001

张三

001

王老师

1002

李四

002

赵老师

1003

王五

001

王老师

1001

张三

002

赵老师

这张表描述了学生和老师的关系:1个学生可能有多个老师,1个老师有多个学生,多对多关系!
上面的表既不满足第一范式,也不满足第二范式。
修改使其满足第一范式,学生编号和教师编号联合起来做主键,复合主键(PK:学生编号+教师编号)

学生编号

+教师编号(PK)

学生姓名

教师姓名

1001

001

张三

王老师

1002

002

李四

赵老师

1003

001

王五

王老师

1001

002

张三

赵老师

经过修改之后,以上的表满足了第一范式,但不满足第二范式,因为张三依赖1001,王老师依赖001,显然产生了部分依赖。“张三”,“王老师”都重复了,因此产生了数据冗余,空间浪费。
为了让以上的表满足第二范式,使用三张表来表示多对多的关系!!!!
学生表:

学生编号

学生姓名

1001

张三

1002

李四

1003

王五

教师表:

教师编号

教师姓名

001

王老师

002

赵老师

学生教师关系表:

id(pk)

学生编号(fk)

教师编号(fk)

1

1001

001

2

1002

002

3

1003

001

4

1001

002

总结:多对多,三张表,关系表两个外键!!!

6.3 第三范式

第三范式建立在第二范式的基础之上,要求每个非主键字段都要直接依赖主键,不要产生传递依赖。

学生编号

学生姓名

班级编号

班级名称

1001

张三

01

一年级一班

1002

李四

02

一年级二班

1003

王五

03

一年级三班

1004

赵六

03

一年级三班

以上表的设计师描述班级和学生的关系,1对多,1个教室中有多个学生。
满足第一范式,有主键,原子性
满足第二范式,主键不是复合主键,是单一主键,没有产生部分依赖。
不满足第三范式,一年级一班依赖01,01依赖1001,产生了传递依赖。
不符合第三范式的要求,产生了数据的冗余。
可以修改为两张表:
班级表:

班级编号(PK)

班级名称

01

一年级一班

02

一年级二班

03

一年级三班

学生表:

学生编号(PK)

学生姓名

班级编号(FK)

1001

张三

01

1002

李四

02

1003

王五

03

1004

赵六

03

总结:一对多,两张表,多的表加外键!!!