数据库MySQL
- MySql常用命令(不区分大小写, ; 表示结束)
- SQL语句的分类
- 查询语句
- 排序(order by)
- 以上综合使用
- 数据处理函数
- 大总结
- distinct 关键字
- 表连接查询
- 子查询
- union 合并查询结果集
- limit(重点)
- 创建表(create)
- 删除表(drop)
- 插入数据(insert)
- 修改(update)
- 删除数据(delete)
- 约束(constraint)重点
- 存储引擎(了解)
- 事务(重点)
- 索引(index)
- 视图(view)
- DBA常用命令(不常用):
- 数据库设计范式
MySql常用命令(不区分大小写, ; 表示结束)
数据库中最基本的单元 --> 表 --> 表比较直观
\c 中止指令
- 登录mysql:
mysql -uroot -p
- 退出mysql:
exit;
- 创建一个数据库
mysql> create database ****;
- 查看数据库
mysql> show databases;
- 使用数据库
mysql> use ****;
- 查看数据表
mysql> show tables;
- 导入数据表,文件路径中不能包含中文
mysql> source 文件路径(如:D:\mysql\test.sql)
- 查看表结构
mysql> desc 表名
SQL语句的分类
分为:
-
DQL(Data Query Language):
数据查询语言(凡是带有select关键字的都是查询语句) select...
-
DML(Data Mainipulation Language):
数据操作语言(凡是对表当中的数据进行增删改的都是DML) insert,delete,update
-
DDL(Data Definition Language):
数据表定义语言(主要操作表结构,不是表中的数据) 凡是带有create,drop,alter都是DDL
-
TCL(Transactional Control Langguage):
事务控制语言 事务提交->commit,事务回滚->rollback
-
DCL(Data Control Language):
数据控制语言 如:授权grant、撤销权限revoke
查询语句
-
简单表查询:
*查询 -> 效率低、可读性差,实际开发中不建议
selsec * from 表名
- 查询各别字段,select后可以跟着字段名或者字面量
selsec 字段名,字段名 from 表名
selsec "字面量" from 表名
- 给查询的关键字取别名 -> as,as关键字也可以省略
不会修改表中的字段名
select 字段名,字段名 as 别名 from 表名
select 字段名,字段名 别名 from 表名 //加空格
select 字段名,字段名 '别名' from 表名 //若别名中有空格可以使用,加''
- 字段可以使用数学表达式,如:
select name,i*12 '计数' from table
- 条件查询
select
name1,name2,name3, ..
from
表名
where
条件;
条件类型
-
不等于 --> != ,<>
-
select sal from tabl where sal != 300;
-
select sal from tabl where <> 300;
-
等于 --> =
select sal from tab where sal = 200;
-
介于两个值之间 --> between … and … --> 必需遵循左小右大
select sal from tab where sal between 100 and 200;
-
查询为空的值 --> is null,不为空 --> not is null, null不能使用null衡量
select name from tab where name is null;
select name from tab where name not is null;
-
并且 and
select sal,name from tab where sal > 10 and name = '张';
-
或者 or
select empo from tabl where empo = '焊工' or empo = ‘电工’;
- and 和 or 同时出现的话,优先级 and 大于 or,可以使用‘小括号()‘来规定
-
包含 in ,不是区间,in里面是具体的值,相当于多个or
not in 不包含select sal from tab where sal in (100,500,200);
select sal from tab where sal not in (100,500,200);
-
like 模糊查询,支持
%
和_
匹配,%
匹配任意多个字符,_
任意一个字符,如:
------------------------- % 的使用------------------------------------
//找出名字 name 中包含 ma 的值
select name from tab where name like '%ma%';
//找出名字 name 以k 结尾的
select name from tab where name like 'k%';
//找出名字 name 以bg 开头的
select name from tab where name like '%bg';
------------------------- _ 的使用------------------------------------
//查找第二个字母是 s 的名字name
select name from tab where name like '_s%';
//查找第三个字母是 t 的名字name
select name from tab where name like '__t%';
//找出name中带有 符号 _ 的值,要使用 \_ 进行转义
select name from tab where name like '%\_%';
排序(order by)
- 排序 --> order by ,默认升序
select name,sal from tab order by sal;
- 指定降序 --> desc
select name,sal from tab order by sal desc;
- 指定升序 --> asc (默认)
select name,sal from tab order by sal asc;
- 多条件排序,如 先根据sal升序,再根据name升序排序,
sal asc
相等才能执行name asc
select name,sal from tab order by sal asc , name asc;
以上综合使用
select
....
from
....
where
....
order by
...
各关键字的执行顺序:
第一步:from ,第二步:where,第三步:select,第四步:order by (排序总是最后一步)
例如:找出工资在1250到3000之间的员工信息,要求按照薪资的降序排列
select
name,sal
from
tab
where
sal between 1250 and 3000
order by
sal desc;
数据处理函数
数据处理函数又称为单行处理函数
单行处理函数的特点:一个输入对应一个输出
多行处理函数的特点:多个输入,对应一个输出
单行处理函数
- 常见的单行处理函数:
- lower 转换小写
- upper 转换大写
- substr 取子串,substr(字符串,起始下标,截取长度),起始下标从1开始
- length 计算长度
- concat 字符串拼接
- trim 去空格
- str_to_date 将字符串转日期,将varchar类型转为data类型
- date_format 格式化日期,将data类型转换为具有一定格式的varchar类型
- format 设置千分位
- round 四舍五入
- rand() 生成随机数
- ifnull 可以将null转换成一个具体的值 --> ifnull(数据,被当作哪个值),**null参数数学运算,输出结果都为null**
- case...when...then...when...then...else...end 当什么时候做什么(不修改数据库,只是操作查询结果)
举个例子:
//lower 转换小写
Select lower(name) from tab;
//upper 转换大写
Select upper(name) from tab;
//concat 字符串拼接
select concat(name,sal) from tab;
//length 取长度
select length(name) from tab;
// trim 去空格
select name from tab where name = trim(' tree');
// round 四舍五入,0保留整数,-1保留到十位
select round(sal,0) from tab;
//ifnull(数据,被当作哪个值),计算年薪
select (sal + ifnull(emp,0))*12 from tab;
//case...when...then...when...then...else...end,当员工的工作岗位是MANGER时工资上调10%,为SAILSMAN时,工资上调50%,其他正常
select
name,
job,
(case job when 'MANGER' then sal*1.1 when 'SAILSMAN' then sal*1.5 else sal end) as newsal
from
tab;
------------------稍微整合一下---------------------------
//首字母大写
select concat(upper(substr(name,1,1)),substr(name,2,length(name) - 1)) as result from tab;
str_to_date(‘字符日期’,‘日期格式’)
-
mysql的日期格式
- %Y 年
- %m 月
- %d 日
- %h 时
-
%i 分
%s 秒
insert into t_user(id,name,birth) values(01,'jack',str_to_date('01-2-1999','%d-%m-%Y'));
date_format(日期类型数据,‘日期格式’)
select id, name, date_format(birth,'%m/%d/%Y') as birth from t_user;
多行处理函数(分组函数)
多行处理函数的特点:输入多行,最终输出一行
- count 计数
- sum 求和
- sum 平均数
- max 最大值
- min 最小值
注意:
- 分组函数在使用的时候必须先分组,然后才能使用。如果没有对数据进行分组,整张表 默认 为一组。
- 分组函数不需要提前对NULL进行处理,自动忽略NULL
- 所有的分组函数可以组合起来一起使用
- 分组函数中不能直接使用where,只能是having
分组查询
在实际应用中,可能需要先进行分组,然后对每一组的数据进行操作,这时需要使用到分组查询。
select
...
from
...
where
...
group by
...
order by
...
执行顺序:from --> where --> group by --> select --> order by
为什么分组函数不能直接使用在where后面?
因为分组函数在使用的时候必须先分组在使用,where执行的时候,还没有分组。所以where后面不能出现分组函数。
使用having可以对分完组之后的数据进行进一步过滤,having不能单独使用,having不能代替where,having必须和group by联合使用
重点结论:
在一条select语句当中,如果有group by语句的话,select后面自能跟:参加分组的字段,以及分组函数,其他的一律不能跟。
-
例题:
- 找出每个部门,不同工作岗位的最高薪资??
//技巧:两个字段联合成1个字段来看
select depton,job,max(sal) from tab group by depton,job;
- 找出每个部门最高薪资,要求显示最高薪资大于3000的??
//写法一:使用having,效率较低
select depton,sal from tab group by depton having max(sal) > 3000;
//写法二:使用where,where中不能使用分组函数
select depton,max(sal) from tab where sal > 3000 group by depton;
/**
*where和having,在where能够实现的情况下,首选where
*/
- 找出每个部门平均薪资,要求显示平均薪资大于2500??
//在where无法实现的情况下,才使用having
select depton,avg(sal) from tab group by depton having avg(sal) > 2500;
大总结
查询语句格式顺序如下:
select
...
from
...
where
...
group by
...
having
...
order by
...
- 执行顺序:from --> where --> group by --> having --> select --> order by
-
例题:
- 找出每个岗位的平均薪资,要求显示平均薪资大于1500的,除MANAGER之外,要求按照平均薪资降序显示 ??
select
job,avg(sal) as avgSal
from
tab
where
job <> 'MANAGER'
group by
job
having
avg(sal) > 1500
order by
avgSal desc;
distinct 关键字
distinct --> 把查询结果,去除重复记录,只能出现在所有字段最前端
//distinct在job和name两个字段之前,表示将两个字段联合起来去重
select distinct job,name from tab;
表连接查询
跨表查询,多张表联合起来查询数据
连接查询分类
根据表连接的方式分类:
- 内连接
- 等值连接
- 非等值连接
- 自连接
- 外连接
- 左外连接(左连接)
- 右外连接(右连接)
- 全连接
两张表连接没有任何条件限制:
select dname,ename from etab,dtab;
当两张表进行连接查询,没有任何条件限制的时候,最终查询结果条数,是两张表条数的乘积,这种现象称为笛卡尔现象。
解决笛卡尔现象,查询次数没有减少。select dname,ename from etab,dtab where etab.ename = dtab.dname;
表起别名,很重要,效率问题。select d.dname, e.ename from etab e, dtab d where e.ename = d.dname;
注意:
通过笛卡尔积现象得出,表的连接次数越多效率越低,尽量避免表的连接次数。
内连接
A、B 两种表没有主次关系
等值连接
例题:查询每个员工所在部门名称,显示员工名和部门名?
//SQL92语法,结构不清晰,和后期进一步筛选条件,都放在了where后面。
select
e.name, d.dname
from
etab e, dtab d
where
e.depton = d.depton and 后面加条件;
//SQL99语法
select
e.name,d.dname
from
etab e
inner join
dtab d
on
e.depton = d.depton;
SQL99语法,表连接的条件是独立的,连接后,如果需要进一步筛选,再往后继续加where
//inner可以省略,可读性更好
select
...
from
a
inner join
b
on
a和b的连接条件
where
筛选条件;
非等值连接
- 条件不是一个等量关系,称为非等值连接。
例题:找出每个员工的薪资登记,要求显示员工名、薪资、薪资等级??
select
e.ename ,e.sal ,s.grade
from
etab e
join
stab s
on
e.sal between s.losal and s.hisal;
自连接
例题:查询员工的上级领导,要求显示员工名和对应的领导名??(员工信息与领导信息都存在员工表中)
- 技巧:一张表看成两张表。
select
e.name as '员工名', b.name as '领导名'
from
emp e
join
emp b
on
e.mgr = b.empo; //员工的领导编号 = 领导的员工编号
外连接
内连接的特点:完全能够匹配上这个条件的数据查询出来。
外连接特点:未匹配到的数据也可以查询出来。
right 代表:表示将join关键 右边 的这张表看成 主表,主要为了将这张表的数据 全部查出来,捎带着关联查询左边的表。
在外连接当中,两张表,产生了主次关系。
left 同理,左边 主表 全部查出来。
-----------------------右连接right-----------------------------
//outer 可省略,带着可读性强
select
e.ename, d.dname
from
etab e right outer join dtab d
on
e.depton = d.depton;
-----------------------左连接left-----------------------------
//outer 可省略
select
e.ename, d.dname
from
etab e left join dtab d
on
e.depton = d.depton;
带有right的是右外连接,又称为右连接。
带有left的是左外连接,又称为左连接。
任何一个右连接都有左外连接的写法。
任何一个左外连接都有右外连接的写法。
外连接的查询结果条数一定大于内连接的查询结果条数。
- 例题:查询每个员工的上级领导,要求显示所有员工的名字和领导名??
select
a.ename as '员工名' ,b.ename as '领导名‘
from
etab a
left join
etab b
on
a.mgr = b.empno;
三张表、四张表的连接方式
一条SQL中 内连接 和 外连接 可以混合使用。
select
...
from
a
join
b
on
//a和b 的连接条件
join
c
on
//a和c 的连接条件
join
d
on
//a和d 的连接条件
- 例题:找出每个员工的部门名称以及工资等级,要求显示员工名、部门名、薪资、薪资等级??
select
e.ename,e.sal,d.dname,s.grade
from
emp e
join
dept d
on
e.deptno = d.deptno
join
salgrade s
on
e.sal between s.losal and s.hisal;
- 例题:找出每个员工的部门名称以及工资等级,还有上级领导,要求显示员工名、领导名、部门名、薪资、薪资等级??
select
e.ename, e.sal, d.dname, s.grade, l.ename
from
emp e
join
dept d
on
e.deptno = d.deptno
join
salgrade s
on
e.sal between s.losal and s.hisal
left join
emp l
on
e.mgr = l.empno;
子查询
- 什么是子查询?
select语句中嵌套select语句,被嵌套的select语句成为子查询。
子查询都可以出现在哪里??
select
...(select)..
from
...(select)..
where
...(select)..
where语句中的子查询
- 例题:找出比最低工资高的员工姓名和工资??
//第一步,查询最低工资是多少
select min(sal) from emp;
//第二步,找出>800的
select ename,sal,from emp where sal > 800;
//第三步,合并
select ename,sal from emp where sal > (select min(sal) from emp);
from语句中的子查询
- 注意:from后面的子查询,可以将子查询的查询结果当作一张临时表。
- 例题:找出每个岗位的平均工资的薪资等级??
//先查询出每个岗位的平均工资
select job ,avg(sal) as avgsal from emp group by job;
//将上面查询出的结果看作一张 表t,与 薪资表salgrade 进行连接查询
select
t.*, s.grade
from
(select job ,avg(sal) as avgsal from emp group by job) t
join
salgrade s
on
t.avgsal between s.losal and s.hisal;
select中的子查询(了解即可)
注意:select后面的子查询只能一次返回一条结果,多于一条,就报错。
- 例题: 找出每个员工的部门名称,要求显示员工名,部门名??
select
e.ename, (select d.name from dept d where e.deptno = d.deptno) as dname
from
emp e;
union 合并查询结果集
union的效率更高一些,对于表连接来说,每连接一次新表,则匹配的次数满足笛卡尔积,成倍的翻。
但是union可以减少匹配的次数。在减少匹配次数的情况下,还可以完成两个结果集的拼接。
- 例题:查询工作岗位是MANAGER和SALESMAN的员工??
select ename, job from emp where job = 'MANAGER';
union
select ename, job from emp where job = 'SALESMAN';
-
注意:
- union在进行结果集的合并的时候,要求结果集的列数相同
- 结果集合并时列和列的数据类型也要相同(MySQL中不报错,Oracle中会报错)
limit(重点)
- limit作用:将查询结果集的一部分取出来,通常使用在分页查询当中。
limit怎么使用: | |
---|---|
完整用法:limit startIndex length | |
startIndex是起始下标默认从0开始,length 是长度 | |
缺省用法:limit 5; 取前5条数据 |
- 例题:按照薪资降序,取出排名在前5名的员工?
select
ename.sal
from
emp
order by
sal desc
limit 0,5;
-
注意:limit是在order by 之后执行的!!!!
-
例题:取出工资排名在3-5名的员工???
select
ename, sal
from
emp
order by
sal desc
limit
2,3;
分页
-
每页显示3条记录
- 第一页:limit 0,3
- 第二页:limit 3,3
- 第三页:limit 6,3
- 第四页:limit 9,3 每页显示pageSize条记录
- 第pageNo页:limit n, pageSize
- n = (pageNo - 1) * pageSize
关于以上SQL语句的总结
select
...
from
...
where
...
group by
...
having
...
order by
...
limit
...
执行顺序:
from --> where --> group by --> having --> select -->order by --> limit
创建表(create)
建表的语法格式
create table 表名(
字段名1 数据类型,
字段名2 数据类型,
字段名3 数据类型
);
- 表名:建议以
t_
或者tab1_
开始,可读性强,见表名意 - 所有标识符都是全部小写,单词和单词之间使用下划线进行衔接。
快速创建表
- 原理:
- 将一个查询结果当作一张新表创建。
- 这个可以完成表的快速复制。
- 表创建出来,同时表中的数据页存在。
create table emp2 as select * from emp;
create table emp2 as select ename,empon from emp where jop = 'MANEGER';
mysql中常见的数据类型
常见的数据类型:
- varchar:可变长度的字符串,根据实际长度动态分配空间。
- char:定长字符串,分配固定长度的空间存储数据,使用不当可能会导致空间浪费。
- int:数字中的整数型,默认11。
- bigint:数字中的长整型。
- float:单精度浮点型。
- double:双精度浮点型。
- datetime:长日期,包括年月日时分秒信息,默认格式:%Y-%m-%d %h-%i-%s。
- date:短日期,只包括年月日信息,默认格式:%Y-%m-%d。
- clob:字符大对象,最多可存储4G的字符串。如存储长文章。超过255个字符的可使用clob来存储
- blob:二进制大对象,专门用来存储图片、声音、视频等流媒体数据。往blob插入视频等数据,需要使用IO流。
案例:创建一个学生表
create table t_student(
no int,
name varchar(35),
sex char(1), default 'm',
age int(3),
email varchar(255)
);
删除表(drop)
//直接删除,表不存在会报错
drop table t_student;
//存在,再删除
drop table if exists t_student;
插入数据(insert)
语法格式:
字段名和值要一一对应,数量对应,数据类型对应。
insert into 表名 (字段名1,字段名2,...) values(值1,值2,...);
- insert语句执行成功,必会多一条数据。
- 前面字段名都省略,等于都写上,后面所有值也要都写上 `insert into t_student values(2,'jack','m',20,'123@qq.com');`
- 一次插入多条记录
insert into t_user(id,name,birth) values
(01,'jack',now()),
(02,'async',now()),
(03,'luccy',now());
插入日期格式的数据
str_to_date(‘字符日期’,‘日期格式’)
-
mysql的日期格式
- %Y 年
- %m 月
- %d 日
- %h 时
-
%i 分
%s 秒
insert into t_user(id,name,birth) values(01,'jack',str_to_date('01-2-1999','%d-%m-%Y'));
date_format(日期类型数据,‘日期格式’)
select id, name, date_format(birth,'%m/%d/%Y') as birth from t_user;
使用mysql函数获取系统当前时间:
- now(),获取的时间带有,时分秒信息,是datetime类型。
修改(update)
- 没有条件限制会导致所有数据更新。
语法格式:
update 表名 set 字段名1=值1,字段名2=值2,... where 条件;
// 例子
update t_student set name = '张三', birth = '2000-10-11', creat_time = now() where no = 2;
删除数据(delete)
- 没有 where 条件,表中所有数据会全部删除。
语法格式:
delete from 表名 where 条件;
//例子
delete from t_student where np = 2;
- delete删除的原理
- 表中的数据被删除了,但是这个数据在硬盘上的真实存储空间不会被释放!!
- 优点:支持回滚,后悔了可以在回复
- 缺点:删除效率较低
回滚操作:
start transaction; //开启事务
delete from dept_bak; //删除数据
rollback; //回滚恢复数据
- truncate语句删除数据原理
- 效率比较高,表被一次截断,物理删除
- 删除表中数据,表还在
- 缺点:不支持回滚
- 优点:快速
//用法:
truncate table dept_bak;
约束(constraint)重点
在创建的时候,我们可以给表中的字段加上一些约束,来保证这个表中数据的完整性、有效性!
- 常见约束:
- 非空约束:not null
- 唯一性约束:unique
- 主键约束:primary key (简称PK)
- 外键约束:foreign key(简称FK)
- 检查约束:check(mysql不支持,oracle支持)
非空约束 not null
非空约束not null约束的字段不能为NULL
create table t_vip(
id int,
name varchar(35) not null
);
唯一性约束 unique
唯一性约束unique约束的字段不能重复,但是可以为NULL。
create table t_vip(
id int,
name varchar(35) unique,
email varchar(255)
);
- 例题:要求name和email两个字段联合起来具有唯一性??
create table t_vip(
id int,
name varchar(35),
email varchar(255),
unique(name,email)
);
约束没有添加在列的后面,这种约束被称为表级约束。 需要给多个字段联合起来添加某一个约束的时候,需要使用表级约束。
unique和not null合用
在mysql中,某个字段同时被not null
和 unique
同时约束,该字段自动变为主键字段(oracle中不一样)
create table v_vip(
id int,
name varchar(35) not null unique //声明为主键PRI
);
主键约束(primary key)重点
- 主键值是每一行记录的唯一标识。
- 主键值是每一行记录的身份证号!!!
- 任何一张表都要有主键,没有主键,表无效。
- 主键的特征: not null + unique (主键值不能为null ,且同时不能重复)
添加主键方法:
- 一张表,主键约束只能有一个
//使用主键约束
create table v_vip(
//一个字段做主键,称为单一主键
id int primary key,
name varchar(35)
);
//使用表级约束
create table v_vip(
id int,
name varchar(35),
primary key(id)
);
create table v_vip(
id int,
name varchar(35),
email varchar(255),
//id和name联合起来做主键,复合主键,开发中不建议使用。
primary key(id,name)
);
主键除了,单一主键和复合主键之外,还可以这样进行分类?
- 自然主键,主键值是一个自然数,和业务没有关系。(建议使用)
- 业务主键,主键值和业务紧密关联,例如拿银行卡账号做主键值。
在mysql中,有一种机制,可以帮助我们自动维护一个主键值?
create table v_vip(
//设置主键值为自增,从1开始自增
id int primary key auto_increment,
name varchar(35),
email varchar(255)
);
外键约束(foreign key,简称PK)重点
例:创建学生和班级信息表??
-
t_student
表中的cno
的值只能是t_class
表中classno
的值
//班级表,父表
create table t_class(
classno int primary key, //班级编号,主键
classname varchar(255) //班级名称
);
//学生信息表,子表
create table t_student(
no int primary key auto_increment, //学生编号,主键
name varchar(35), //学生名称
cno int, //班级编号
foreign key(cno) references t_class(classno) //添加外键约束
);
- 删除表的顺序
- 先删子,在删父 - 创建表的顺序
- 先创建父,再创建子 - 删除数据的顺序
- 先删子,再删父 - 插入数据的顺序
- 先插入父,再插入子
- 子表中的外键引用父表中的某个字段,被引用的字段不一定为主键,但至少具有
unique
约束。- 外键中的值可以为NULL。
存储引擎(了解)
- 存储引擎是MySQL中特有的术语,其他数据库中没有。
- 存储引擎是一个表存储/组织数据的方式。
- 不同的存储引擎,表存储数据的方式不同。
给表添加指定的“存储引擎”
//查看表创建的结构
show create table t_student;
可以在建表的时候给表指定存储引擎
CREATE TABLE `user` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(20) NOT NULL,
`password` varchar(20) NOT NULL,
`gender` varchar(2) DEFAULT NULL,
`email` varchar(50) DEFAULT NULL,
`telephone` varchar(20) DEFAULT NULL,
`introduce` varchar(100) DEFAULT NULL,
`activeCode` varchar(50) DEFAULT NULL,
`state` int(11) DEFAULT '0',
`role` varchar(10) DEFAULT '普通用户',
`registTime` timestamp(6) NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4
在建表的时候可以在最后小括号的 “)” 的右边使用:
-
ENGINE来指定存储引擎
-
CHARSET来指定这张表的字符编码方式
结论:
- mysql默认的存储引擎是:InnoDB
- mysql默认的字符集编码方式是: utf8
可以在建表的时候声明存储引擎:
create table t_table(
name varchar(35) primary key,
age int(3)
)engine=InnoDB default charset=gbk;
查看MySQL支持的存储引擎
根据数据的版本,支持的存储引擎会有不同。
show engines \G
mysql支持9大存储引擎:
*************************** 1. row ***************************
Engine: MEMORY
Support: YES
Comment: Hash based, stored in memory, useful for temporary tables
Transactions: NO
XA: NO
Savepoints: NO
*************************** 2. row ***************************
Engine: MRG_MYISAM
Support: YES
Comment: Collection of identical MyISAM tables
Transactions: NO
XA: NO
Savepoints: NO
*************************** 3. row ***************************
Engine: CSV
Support: YES
Comment: CSV storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 4. row ***************************
Engine: FEDERATED
Support: NO
Comment: Federated MySQL storage engine
Transactions: NULL
XA: NULL
Savepoints: NULL
*************************** 5. row ***************************
Engine: PERFORMANCE_SCHEMA
Support: YES
Comment: Performance Schema
Transactions: NO
XA: NO
Savepoints: NO
*************************** 6. row ***************************
Engine: MyISAM
Support: YES
Comment: MyISAM storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 7. row ***************************
Engine: InnoDB
Support: DEFAULT
Comment: Supports transactions, row-level locking, and foreign keys
Transactions: YES
XA: YES
Savepoints: YES
*************************** 8. row ***************************
Engine: BLACKHOLE
Support: YES
Comment: /dev/null storage engine (anything you write to it disappears)
Transactions: NO
XA: NO
Savepoints: NO
*************************** 9. row ***************************
Engine: ARCHIVE
Support: YES
Comment: Archive storage engine
Transactions: NO
XA: NO
Savepoints: NO
9 rows in set (0.00 sec)
MySQL常见的存储引擎
-
MyISAM存储引擎:
-
管理的表具有以下特征
-
- 使用三个文件表示每个表
- 格式文件 - 存储表结构的定义(mytable.frm)
- 数据文件 - 存储表行的内容(mytable.MYD)
- 索引文件 - 存储表上索引(mytable.MYI):索引是一本书的目录,,缩小扫描范围,提高查询效率。
- 使用三个文件表示每个表
-
可被转换为压缩、、只读表来节省空间。 (优点)
提示:对于一张表来说,只要是主键,或者加有unique约束的字段上会自动创建索引。
MyISAM不支持事务,安全性低。
InnoDB存储引擎
-
mysql默认的存储引擎,同时也是一个重量级的存储引擎。
InnoDB支持事务,支持数据库崩溃后自动恢复机制。
InnoDB存储引擎最主要的特点是:非常安全。 -
管理的表具有一下主要特征:
- 每一个 InnoDB表在数据库目录中以.frm格式文件表示
- InnoDB表空间tablespace被用于存储表的内容(表空间是一个逻辑名称,表空间存储数据 + 索引)
- 提供一组用来记录事务性活动的日志文件
- 用COMMIT、SAVEPOINT及ROLLBACK支持事务处理
- 提供全ACID兼容
- 在MySQL服务器崩溃后提供自动恢复
- 多版本(MVCC)和行级锁定
- 支持外键及引用的完整性,包括联级删除和更新。
-
innoDB最大的优点支持事务,以保证数据安全。
MEMORY存储引擎
-
使用MEMORY存储引擎的表,其数据存储在内存中,且行的长度固定。
-
这两个特点使得MEMORY存储引擎非常快。
-
MEMORY 存储引擎管理的表具有一下特征:
- 在数据库目录内,每个表均以.frm格式的文件表示。
- 表数据及索引在存储在内存中(目的就是快,查询快)
- 表级锁机制
- 不能包含TEXT或BLOB字段。
-
MEMORY 存储索引以前被称为HEAP引擎。
事务(重点)
一个事务就是一个完整的业务逻辑。是一个最小的工作单元,不可再分。
- 例如:银行转账,A向B转100,这是A账户扣除100,B账户加上100,这个操作要么同时成功,要么同时失败。
只有DML语句有事务一说,insert、update、delete,保证数据安全。
本质上,一个事务其实就是多条DML语句同时成功,或者同时失败。
事务(transaction)的实现
提交事务:
- 清空事务性活动的日志文件,将数据全部彻底持久化到数据库表中。
- 提交事务标志着,事务结束,并且是一种全部成功的结束。
回滚事务:
- 将之前所有的DML操作全部撤销,并且清空事务性活动的日志文件。
- 回滚事务标志着,事务的结束,并且是一种全部失败的结束。
提交事务:commit; 语句
start transaction; //开启事务
.....//一系列DML语句
commit; //提交事务
回滚事务:rollback; 语句 (回滚只能回滚带上一次提交点)
start transaction; //开启事务
.....//一系列DML语句
rollback; //回滚事务
在mysql当中默认的事务行为:
- 默认情况下,支持自动提交事务的。(自动提交)
- 什么是自动提交?
- 每执行一条DML语句,则提交一次!
关闭自动提交机制命令:
start transaction;
事务包括4个特性
- 原子性
- 说明事务是最小的工作单元,不可拆分。 - 一致性
- 所有事务要求,在同一个事务当中,所有操作必须同时成功,或者同时失败,以保证数据的一致性。 - 隔离性
- A事务和B事务之间具有一定的隔离。 - 持久性
- 事务最终结束的一个保障,事务提交,就相当于将没有保存到硬盘上的数据保存到硬盘上。
事务的隔离性
4个事务的隔离级别
- 读未提交:read-uncommitted(最低的)
- 事务A可以读取到事务B未提交的数据。脏读现象(Dirty-Read),一般都是理论上的。大多数数据库隔离级别都是二档起步。
- 没提交就读取到。
- 读已提交:read-committed
- 事务A只能读取到事务B提交后的数据。解决脏读,但不可重复读取数据
- 不可重复读:事务开启后,第一次读取到的数据3条,当前事务还没有结束,可能第二次再读取的时候,读到的数据是4条,3不等于4,称为不可重复读取。
- 这种隔离级别是比较真实的数据,每一次读到的数据是绝对的真实。oracle数据库默认的隔离级别是:read-committed
- 提交之后才能读到
- 可重复读:repeatable-read
- 事务A开启后,不管多久,每次在事务A中读取到的数据都是一致的。即使事务B将数据已经修改,并且提交了,事务A读取到的数据还是没有发生改变。
- 解决了不可重复读问题,可能会出现幻读,不够真实!
- MySQL中默认的隔离级别,可重复读。
- 提交之后也读不到,永远读取到的都是刚开启事务时的数据。
- 序列化/串行化(最高的):serializable
- 最高隔离级别,效率最低,解决了所有问题。
- 表示事务排队,不能并发。
- 每次读取到的数据都是最真实的,并且效率是最低的。
隔离级别验证
//查看隔离级别
SELECT @@tx_isolation; //新版本已经弃用了
SELECT @@transaction_isolation; //新版本使用这个查看,mysql8.0+
read-uncommitted
//设置事务的隔离级别
mysql> set global transaction isolation level read uncommitted;
//---------------------事务B操作--------------------------//
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into t_user(name) values('wangwu');
Query OK, 1 row affected (0.01 sec)
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
//---------------------事务A操作--------------------------//
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t_user; //在事务B 操作事务未提交,就读取到数据
+--------+
| name |
+--------+
| wangwu |
+--------+
1 row in set (0.00 sec)
mysql> select * from t_user; //当事务B 执行rollback回滚事务后,事务A 中的数据就没了
Empty set (0.00 sec)
read-committed
mysql> set global transaction isolation level read committed;
//---------------------事务B 操作--------------------------//
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into t_user values('zhangsan'); //执行insert ,但未提交事务
Query OK, 1 row affected (0.00 sec)
mysql> commit; //提交事务
Query OK, 0 rows affected (0.00 sec)
//---------------------事务A 操作--------------------------//
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t_user; //事务B 执行insert之前
Empty set (0.00 sec)
mysql> select * from t_user; //事务B 执行insert之后
Empty set (0.00 sec)
mysql> select * from t_user; //事务B commit提交事务后,执行
+----------+
| name |
+----------+
| zhangsan |
+----------+
1 row in set (0.00 sec)
repeatable-read
mysql> set global transaction isolation level repeatable read;
//---------------------事务B 操作--------------------------//
mysql> start transaction; //开启事务
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t_user; //先查询表中数据
+----------+
| name |
+----------+
| zhangsan |
+----------+
1 row in set (0.00 sec)
//向t_user表中,插入3条数据
mysql> insert into t_user(name) values('jack'),('wangwu'),('daniu');
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from t_user;
+----------+
| name |
+----------+
| zhangsan |
| jack |
| wangwu |
| daniu |
+----------+
4 rows in set (0.00 sec)
mysql> commit; //提交事务
Query OK, 0 rows affected (0.00 sec)
//---------------------事务A 操作--------------------------//
mysql> start transaction; //开启事务
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t_user; //事务B,执行insert之前查询
+----------+
| name |
+----------+
| zhangsan |
+----------+
1 row in set (0.00 sec)
mysql> select * from t_user; //事务B,执行insert之后查询
+----------+
| name |
+----------+
| zhangsan |
+----------+
1 row in set (0.00 sec)
mysql> select * from t_user; //事务B,执行commit 提交事务后查询
+----------+
| name |
+----------+
| zhangsan |
+----------+
1 row in set (0.00 sec)
serializable
mysql> set global transaction isolation level serializable;
//---------------------事务B 操作--------------------------//
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t_user;
+----------+
| name |
+----------+
| zhangsan |
| jack |
| wangwu |
| daniu |
+----------+
4 rows in set (0.00 sec)
//---------------------事务A 操作--------------------------//
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t_user;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>_ //当事务B 的操作未提交commit时,事务A 的操作无法进行操作。
//当事务B 将事务提交commit后,事务A 才能继续执行。
+--------------------+
| name |
+--------------------+
| zhangsan |
| jack |
| wangwu |
| daniu |
| serializableUser |
| serializableUser22 |
+--------------------+
6 rows in set (0.00 sec)
索引(index)
索引是在数据库表的字段上添加的,是为了提高查询效率存在一种机制。
一张表的一个字段可以添加一个索引,当然,多个字段联合起来也可以添加索引。
-
Mysql在查询方面主要就两种方式:
- 全表扫描
- 根据索引检索
在MySQL数据库当中索引也需要排序,并且这个索引的排序和TressSet数据结构相同。TreeSet(TreeMap)底层是一个自平衡的二叉树! 在mysql当中索引是一个B-Tree数据结构。
遵循左小右大原则存放,采用中序遍历方式遍历取数据。
索引实现原理
缩小扫描范围,避免全表扫描。
提醒1:在任何数据库当中主键上都会自动添加索引对象,id字段上自动有索引。因为id是PK。另外在MySQL当中,一个字段上如果有unique约束的话,也会自动创建索引对象。
提醒2:在任何数据库当中,任何一张表的任何一条记录在硬盘上都有一个硬盘的物理存储编号。
提醒3:在mysql当中,索引是一个单独的对象,不同的存储引擎以不同的形式存在。在MyISAM存储引擎中,索引存储在一个.MYI文件中。在InnDB存储引擎中,索引存储在一个逻辑名称叫做tablespace的当中。在MEMORY存储引擎中,索引被存储在内存当中。不管索引存储在哪里,索引在mysql当中都是一个树的形势存在。(平衡二叉树:B-Tree)
举个例子:
添加索引条件:
- 数据量庞大
- 该字段经常出现在where后面,以条件的形式存在,也就是说这字段总是被扫描。
- 该字段很少的DML操作,因为DML之后,索性需要重新排序。
建议不要随意添加索引,因为索引也需要维护,太多的话反而会降低系统的性能。
建议通过主键查询,通过unique约束的字段进行查询,效率比较高。
索引的创建和删除
//给emp表的ename字段添加索引,起名:emp_ename_index
create index emp_ename_index on emp(ename);
//删除索引
drop index emp_ename_index on emp;
查看索引
//使用explain 查看语句查询方式
mysql> explain select * from user where email ='19747708@qq.com';
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | user | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 20.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
rows=5扫描了5条记录,type=ALL,说明没有使用索引。
//创建索引
create index email_index on user(email);
//使用explain 查看语句查询方式
mysql> explain select * from user where email ='19747708@qq.com';
+----+-------------+-------+------------+------+---------------+-------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+-------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | user | NULL | ref | email_index | email_index | 203 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+-------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.01 sec)
rows=1扫描了1条记录,type=ref ,说明使用索引。
索引失效
情况1:
避免使用模糊查询的时候以“%”开始,这是一种优化策略。
mysql> explain select * from user where email like '%708';
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | user | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 20.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
情况2:
使用or的时候会失效如果使用or那么要求两边的条件都要有索引,才会走索引,如果其中一边有一个字段没有索引,那么另外一个字段上的索引也会失效,所以不建议使用or。
mysql> explain select * from user where email = '19747708@qq.com' or telephone ='12345678911 ';
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | user | NULL | ALL | email_index | NULL | NULL | NULL | 5 | 36.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
情况3:
使用复合索引的时候,没有使用左侧的列查找,索引失效。
复合索引:两个字段,或者更多的字段联合起来添加一个索引。
create index role_name on user(role,username);
//--------------左侧索引 role---------------------//
mysql> explain select * from user where role = '普通用户';
+----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
| 1 | SIMPLE | user | NULL | ref | role_name | role_name | 43 | const | 3 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
//--------------右侧索引 username-----------------//
mysql> explain select * from user where username = 'as123';
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | user | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 20.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
情况4:
在where当中索引列参加了数学运算,索引失效。
mysql> create index state_index on user(state);
//-------------未添加数学运算----------------//
mysql> explain select * from user where state = 1;
+----+-------------+-------+------------+------+---------------+-------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+-------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | user | NULL | ref | state_index | state_index | 5 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+-------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
//-------------添加数学运算----------------//
//索引 列 state参加数学运算
mysql> explain select * from user where state+1 = 1;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | user | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
情况5:
在where当中索引列使用了函数。
mysql> drop index role_name on user;
mysql> create index name_index on user(username);
//----------------------------------未添加函数---------------------------------//
mysql> explain select * from user where username = 'asd123';
+----+-------------+-------+------------+------+---------------+------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | user | NULL | ref | name_index | name_index | 82 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
//----------------------------------添加函数---------------------------------//
mysql> explain select * from user where lower(username) = 'asd123';
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | user | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
索引分类
索引是各种数据库进行优化的重要手段。优化优先考虑索引。
- 单一索引 :一个字段上添加索引。
- 复合索引:两个字段或者更多的字段上添加索引。
- 主键索引:主键上添加索引。
- 唯一性索引:具有unique约束的字段上添加索引。
- 注意:唯一性比较弱的字段上添加索引用处不大。
视图(view)
站在不同角度去看待同一份数据。
- 可以面向视图对象进行 增删改查 ,对视图对象的 增删改查,会导致原表被操作。(通过操作视图,会影响到原表的数据)
- 简化SQL语句,将复杂的SQL语句直接使用视图对象。
- 使用视图的时候可以像使用tbale一样,视图也是存储在硬盘上,不会消失。
创建视图
- 只有DQL语句才能以view的形式创建。
- 可以对多表连接查询,创建视图
create view user2_view as select * from user;
删除视图
drop view user2_view;
操作视图
//对user2_view 视图进行插入操作
mysql> insert into user2_view(username,password,gender,email) values('jjjj','sss','m','123@qq.com');
Query OK, 1 row affected (0.00 sec)
//查询原表数据,发生改变
mysql> select * from user2;
+----+------------+----------+--------+--------------------+-------------+------------------+------------+-------+----------+----------------------------+
| id | username | password | gender | email | telephone | introduce | activeCode | state | role | registTime |
+----+------------+----------+--------+--------------------+-------------+------------------+------------+-------+----------+----------------------------+
| 1 | | | NULL | NULL | NULL | NULL | NULL | 0 | NULL | 0000-00-00 00:00:00.000000 |
| 3 | as123 | 123456 | 男 | 1974708999@qq.com | 17706058702 | fddfds | NULL | 0 | 普通用户 | 2020-06-13 00:00:00.000000 |
| 4 | sasassa123 | 654321 | 男 | 1974708999@163.com | 17706058703 | asdasff | NULL | 0 | 普通用户 | NULL |
| 5 | tti_12 | 987654 | 男 | 1421842575@12.com | 12346789112 | 测试账户登录账号 | NULL | 0 | 普通用户 | NULL |
| 6 | al_22 | 159753 | 男 | 1974708999@123.com | 12345678911 | 验证信息123 | NULL | 1 | 超级用户 | NULL |
| 0 | jjjj | sss | m | 123@qq.com | NULL | NULL | NULL | 0 | 普通用户 | NULL |
+----+------------+----------+--------+--------------------+-------------+------------------+------------+-------+----------+----------------------------+
6 rows in set (0.00 sec)
DBA常用命令(不常用):
重点掌握数据的导入导出(数据备份)
数据的导出:
- 在windows的dos命令窗口中:
mysqldump bjpowernode>D:\bjpowernode.sql -uroot -p123
- 导出指定的表:mysqldump bjpowernode table>D:\bjpowernode.sql -uroot -p123
数据导入
- 需要先登录到mysql数据库服务器上。
- 然后创建数据库:
create database bjpowernode;
- 使用数据库:
use bjpowernode;
- 然后初始化数据库:
source D:\bjpowernode.sql
数据库设计范式
- 第一范式:要求任何一张表必须有主键,每一个字段原子性不可再分。
- 第二范式:建立在第一范式的基础上,要求所有非主键字段完全依赖主键。
- 第三范式:建立在第二范式的基础上,要求所有非主键字段直接依赖主键。不要产生传递依赖。
- 设计库表设计,遵循范式进行,可以避免表中数据的冗余,空间浪费。
第一范式
最核心,最重要的范式,所有表的设计都需要满足。
必须要有主键,并且每一个字段都是原子性不可拆分。
第二范式
建立在第一范式的基础上,要求所有非主键字段必须完全依赖主键,不要产生部分依赖。
多对多设计:多对多,三张表,关系表两个外键。
第三范式
第三范式建立在第二范式的基础上,要求所有非主键字段必须直接依赖主键,不要产生传递依赖。
一对多设计:两张表,多的表加外键。
总结表的设计
- 多对多设计:多对多,三张表,关系表两个外键。
- 一对多设计:两张表,多的表加外键。
在实际开发中,可能存在一张表字段太多,太庞大,这时候需要拆分表。
- 一对一设计:一对一,外键唯一(FK+UNIQUE)
总结:
- 数据库设计三范式是理论上的。
- 在MySQL当中,表和表之间连接次数越多,效率越低。(笛卡尔集)
- 有时候可能存在冗余,但是为了减少表的连接次数,这样做也是合理的。并且对于开发人员来说,sql语句的编写难度也会降低。