文章目录
- 1.关联查询
- 1.1内连接
- 1.2自然连接
- 1.3外连接
- 1.4自连接
- 2.子查询
- 2.1子查询分类
- 3.联合查询
- 4.存储程序
- 4.1存储过程:输入和输出参数
- 4.2存储函数
- 4.3触发器
- 5.视图
- 5.1作用
- 5.2视图使用
- 6.索引
- 6.1性能分析工具
- 6.2索引的添加
- 6.3InnoDB的索引模型
- 7.数据库的设计和优化
- 7.1数据库的设计
- 7.2数据库优化
- 8.数据库的备份和还原
1.关联查询
条件获取结果分布于多张表,连接多张表进行查询
1.1内连接
内连接将多张表都出现的记录连接展示在结果集
没有主从表之分,结果与连接顺序无关
# 内连接
select ename,sal,dname,emp.deptno FROM emp,dept where emp.deptno = dept.deptno and empno = 7788;
# inner join ... on...
select * from emp inner join dept on emp.deptno = dept.deptno;
# inner join ...using(字段)
select * from emp inner join dept using(deptno);
* 关联字段名称必须一致
* 将关联字段去重
* 必须使用等值连接
1.2自然连接
自然链接都是等值连接,等值连接不一定是自然链接
select * from emp natural join dept
1.3外连接
以驱动表为基准(left前right后),依次遍历并与附属表简历连接;
如果在附属表中找到匹配的记录就连接并展示;如果找不到则以null填充
存在主从表之分,与连接顺序有关
left [outer] join ... on...;左外连接
right [outer] join ... on...;右外连接
select * from emp left join dept on emp.deptno = dept.deptno;
1.4自连接
自身连接自身
查询员工及其领导的姓名。
select e1.ename,e2.ename from emp e1,emp e2 where e1.mgr = e2.empno;
2.子查询
嵌套查询
2.1子查询分类
# 单行子查询:子查询返回的结果是单行单列
select dname from dept where deptno = (select deptno from emp where empno = 7788);
# 多行子查询: 子查询返回的结果是多行
# 查询工资>2000的员工所在的部门名称
select deptno from emp where deptno in (select distinct deptno from emp where sal > 2000) ;
any / all
=any: 相当于in >any:大于最小值 <any:小于最大值
>all:大于最大值 <all:小于最小值
# 查询工资>2000的员工所在的名称
select dname from dept where deptno in (select DISTINCT deptno FROM emp WHERE sal > 2000);
select dname from dept where exists(
select * from emp WHERE sal > 2000 and emp.deptno = dept.deptno);
in 和 exists之间的区别
1.in先执行子查询,将子查询的结果返回给主查询,由主查询继续检索;exists先执行主查询,将主查询的记录一次交给子查询,在子查询中进行匹配,如果匹配则返回true,并将该主查询的结果展示在结果集,如果返回false则不展示。
2.in必须让查询的条件字段和子查询的结果字段匹配:exists不关心子查询的返回结果。
选择:
1.如果查询的结果分布于多张表,选择关联查询:如果结果分布于一张表,关联查询和子查询都可以使用。
2.查询尽量不要过多的嵌套,理论上说尽可能使用关联查询替代子查询提升性能。
3.尽可能先过滤再关联
3.联合查询
union:去重
union all:不去重
select * FROM emp WHERE deptno = 20
union all
select * FROM emp where sal > 2000;
联合查询多个结果集的字段信息需要一致
4.存储程序
运行于服务器端程序
4.1存储过程:输入和输出参数
# 参数模式:
in:默认,输出参数
out:输出参数
inout:输入输出函数
delimiter//;
create procedure sel_emp(in dno int)
begin
select * from emp where deptno = dno;
end //;
call sel_emp(20);
# 输入员工编号查询名称
delimiter //;
create procedure sel_ename(eno int,out name varchar(20))
begin
select ename into name from emp where empno = eno;
end //;
call sel_ename(7788,@name);
select @name;
# 根据名称获取职位
delimiter //;
create procedure sel_job(inout name_job varchar(20))
begin
select job into name_job from emp where ename = name_job;
end //;
set @v_name = 'SCOTT';
call sel_job(@v_name);
select @v_name;
# 选择结构
delimiter //;
create procedure score(score int)
begin
# 声明变量
declare v_level varchar(20);
if score >= 85 then
set v_level = 'A';
elseif score >= 60 then
set v_level = 'B';
else
set v_level = 'C';
end if;
select v_level;
end //;
# 循环结构
delimiter //;
create procedure calc1()
begin
declare i int;
declare sum int;
set i = 1;
set sum = 0;
lip:loop
if i >100 then
leave lip;
end if;
set sum = sum + i;
set i = i+1;
end loop;
while i<= 100 do
set sum = sum + i;
set i = i+1;
end while;
select sum;
end //;
call calc1();
# repeat ... end repeat
delimiter //;
create procedure calc2()
begin
declare i int;
declare sum int;
set i = 1;
set sum = 0;
repeat
set sum = sum + i;
set i = i+1;
until i >100
end repeat;
select sum;
end //;
call calc2();
4.2存储函数
和存储过程类似,作为sql语句的一部分可以进行调用
允许使用返回值
delimiter //;
create function sel_name(eno int)
returns varchar(20)
DETERMINISTIC
begin
declare v_name varchar(20);
select ename into v_name from emp where empno = eno;
return v_name;
end //;
select sel_name(7788);
存储过程和存储函数区别:
1.关键字不同
2.存储过程是通过输入输出参数实现值传递;输入值通过参数传入,输出值通过返回值实现;
3.存储过程可以被当作独立的执行单元运行;但是函数只能当作sql的部分执行
4.3触发器
时间驱动,不能手动调用,不能传递参数
增删改就是一个事件
delimiter //;
create trigger tri_stu
before delete
on stu for each row
begin
insert into student values(old.sid,old.sname,old.age,old.gender);
end //;
5.视图
称为虚拟表,余姚简历在基表之上,动态实现数据的查询
5.1作用
- 隐藏细节(铭感字段)
- 方便实现权限管理
- 字段的组合,分割等操作
5.2视图使用
# 创建视图(存在条件字段被修改的风险,导致视图中的数据量发生改变)
create view view_emp as select * from emp where deptno = 10;
# 创建视图,不允许修改字段
create view view_emp as select * from emp where deptno = 10 with check option;
其他操作和表的一致
6.索引
提示查询效率创建的数据结构
6.1性能分析工具
- explain
解释计划任务(解释器)
explain select * from emp;
type:
const > ref > range > all(全表扫描)
- profiling
sql执行的开销 cpu memory
# 查看是否开启
show variables like '%profiling%';
# 开启profiling
set profiling on;
# 执行sql
# 查看开销
show profiles;
#查看某个sql的开销
show profile cpu,memory for query 281;
- 慢查询
show variables like '%slow_query%';
show_query_log:查看是否开启慢查询
show_query_log_file:慢查询的日志文件
show_query_time:慢查询的时间
6.2索引的添加
- 普通索引
create index index_name on tname(colname); drop index index_name on tname;
- 唯一索引
索引列的值必须唯一
create unique index index_name on tname(colname);
alter table tname drop unique;
主键索引
alter table tname add constraint PK_NAME primary key(colname);
alter table tname drop primary key;
组合索引索引字段是多个,通过第一个字段查询走索引,其他字段走全表
create index index_name on tname(col1,col2);
6.3InnoDB的索引模型
- 主键索引和非主键索引
- 主键索引:也称为聚簇索引,将记录的信息量总维护在叶子节点上;
- 非主键索引:也称为二次索引,叶子节点中维护的是主键的值,然后再在主键的索引树中查询记录,称为回表。
- 添加索引的原则
- 表的数据较大时适合添加索引
- 选择高基数列
- 索引需要维护的,所以不要添加太多索引
- 增删改较多的表不适合添加索引
- 索引字段类型和长度尽可能小
- 尽可能使用主键索引
- 索引失效的状况
1.索引列不要使用函数以及实现运算
select *from userinfo where power(id,2)=64;
selecy *from userinfo where id+2=10;
2.索引列不要使用前导模糊查询
select *from userinfo where phone like '%3659%';
select *from userinfo where phone like '%2524652%';
3.索引列查询尽量不要使用nullt null
4.使用or可能会导致索引失效(条件中每个字段都必须有一个索引)
select *from userunfo where id=8 or phone='15576426853';
7.数据库的设计和优化
7.1数据库的设计
数据库的基本设施
- 三大范式
- 1NF:所有的域是原子性的。
- 2NF:非主键字段必须和主键字段相关;非主键字段不能与部分主键相关(联合主键)
- 3NF:非主键必须和主键直接相关而不能间接相关(依赖传递性)
- 数据库设计的步骤
- E-R关系图
- 表之间的关系
- 一对一:person和recode
- 外键添加唯一约束
- 主键做外键
- 一对多:emp和dept(多的一方添加外键)
- 多对多:student和course
- 创建关系表
- 设计联合主键
7.2数据库优化
- 设计主键字段类型和长度小
- 索引字段尽可能使用固定长度的类型(char -->varchar)
- 查询字段信息时尽可能避免使用limit进行分页查询
- 避免索引失效的状况
- 添加缓存–> redis缓存数据
- 表分区:将整个表的文件物理进行切分(百万)
- 分区分表(读写分离(主从复制))
8.数据库的备份和还原
- 备份
mysqldump -uroot -p dbname tname > d:/a.sql
- 还原
mysql -uroot -p < d:/a.sql