一、视图
1、什么是视图
视图就是通过查询得到一张虚拟表,然后保存下来,下次直接使用即可
2、为什么用视图
当反复用到两张表的连接操作时,可以将连成的表当做视图保存下来,下次直接使用
3、怎么用视图
create view teacher2course as select * from teacher inner join course on teacher.tid = course.teacher_id; 删除视图:drop view teacher2course
4、注意:
在硬盘中,视图只有表结构文件,没有表数据文件 视图通常是用于查询,尽量不要修改视图中的数据
5、思考:开发过程中会不会去使用视图?
不会!视图是mysql的功能,如果你的项目里面大量的使用到了视图, 那意味着你后期想要扩张某个功能的时候这个功能恰巧又需要对视图进行修改, 意味着你需要先在mysql这边将视图先修改一下,然后再去应用程序中修改对应的sql语句, 这就涉及到跨部门沟通的问题,所以通常不会使用视图, 而是通过重新修改sql语句来扩展功能
二、触发器
1、什么是触发器
在满足对某张表数据的增删改的情况下,自动触发的功能称之为触发器
2、如何触发
在对某张表数据的增insert,删delete,改update的情况下,自动触发执行其他的sql语句
3、如何使用
标准语法 create trigger 触发器名字 after insert on 表名 for each row begin sql语句 end ①增 增加数据之前 create trigger tri_before_insert_t1 before insert on t1 for each row begin sql语句 end 增加数据之后 create trigger tri_after_insert_t1 after insert on t1 for each row begin sql语句 end ②删 删除数据之前 create trigger tri_before_delete_t1 before delete on t1 for each row begin sql语句 end 删除数据之后 create trigger tri_after_delete_t1 after delete on t1 for each row begin sql语句 end ③改 修改数据之前 create trigger tri_before_update_t1 before update on t1 for each row begin sql语句 end 修改数据之后 create trigger tri_after_update_t1 after update on t1 for each row begin sql语句 end
4、举例
举例: 创建表格: create table cmd( id int primary key auto_increment, user char(32), prvi char(10), cmd char(64), sub_time datetime, success enum('yes','no') ); create table errlog( id int primary key auto_increment, err_cmd char(64), err_time datetime ); 创建触发器: delimiter $$ # 将mysql默认的结束符由;改为$$ create trigger tri_after_insert_cmd after insert on cmd for each row begin if NEW.success ='no' then insert into errlog(err_cmd,err_time) values(NEW.cmd,NEW.sub_time); end if; end $$ delimiter ; 插入数据: insert into cmd(user,prvi,cmd,sub_time,success) values ('egon','0755','ls -l /etc',now(),'yes'), ('egon','0755','cat /etc/passwd',now(),'no'), ('egon','0755','useradd xxx',now(),'no'), ('egon','0755','ps aux',now(),'yes'); 查看触发器: show create trigger tri_after_insert_cmd; 删除触发器: drop trigger tri_after_insert_cmd;
三、事务
1、什么是事务
开启一个事务可以包含一些sql语句,这些sql语句要么同时成功, 要么一个都别想成功,称之为事务的原子性
事务的作用:
保证了对数据操作的数据安全性
案例:
用交行的卡操作建行ATM机给工商的账户转账
2、事物的四大特性ACID
① A (atomicity)原子性:一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做
② C (consistency)一致性:事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的
③ I (isolation)隔离性:一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的, 并发执行的各个事务之间不能互相干扰。
④ D (durability)持久性:持久性也称永久性(permanence),指一个事务一旦提交, 它对数据库中数据的改变就应该是永久性的, 接下来的其他操作或故障不应该对其有任何影响。
3、语法
语法 开启事物 start transaction 创建表格 create table t1(); 插入数据 insert into t1 values(1,2), insert into t1 values(1,2), insert into t1 values(1,2), 回滚 roll back 提交 commit
4、使用
①创建表 create table user( id int primary key auto_increment, name char(32), balance int ); insert into user(name,balance) values ('wsb',1000), ('egon',1000), ('ysb',1000); ②修改数据之前先开启事务操作 start transaction; ③修改操作 update user set balance=900 where name='wsb'; # 买支付100元 update user set balance=1010 where name='egon'; # 中介拿走10元 update user set balance=1090 where name='ysb'; # 卖家拿到90元 ④回滚到上一个状态 rollback; ⑤开启事务之后,只要没有执行commit操作,数据其实都没有真正刷新到硬盘, 开启事务检测操作是否完整,不完整主动回滚到上一个状态,如果完整就应该执行commit操作 commit; ⑥站在python代码的角度,应该实现的伪代码逻辑(异常捕获,确认无误,提交) try: update user set balance=900 where name='wsb'; 买支付100元 update user set balance=1010 where name='egon'; 中介拿走10元 update user set balance=1090 where name='ysb'; 卖家拿到90元 except: roll back else: commit 那如何检测异常?就用到储存过程
四、存储过程
1、什么是存储过程
存储过程包含了一系列可执行的sql语句,存储过程存放于MySQL中,通过调用它的名字可以执行其内部的一堆sql
2、如何使用存储过程
①直接在mysql中调用 set @res=10; # res的值是用来判断存储过程是否被执行成功的依据,所以需要先定义一个变量@res存储10 call p1(2,4,10); # 报错 call p1(2,4,@res); 查看结果 select @res; # 执行成功,@res变量值发生了变化 ②在python程序中调用,下一节内容 pymysql链接mysql 产生的游表cursor.callproc('p1',(2,4,10)) # 内部原理:@_p1_0=2,@_p1_1=4,@_p1_2=10; cursor.excute('select @_p1_2') print(cursor.fetchall())
3、创建存储过程
语法: delimiter $$ create procedure p1() begin select * from user; end $$ delimiter ; 调用存储过程 call p1(); 举例: delimiter @@ create procedure p1( in m int, # in 表示该形参接收的数据不能被返回出来 in n int, out res int # out 表示该形参接收的数据可以被返回出去 ) begin select * from teacher where tid > m and tid < n; set res=0; # 返回一个值,判断储存过程是否执行 end @@ delimiter ; set @res = 10; # 存一个变量,用来判断执行储存过程后res是否改成0,然后再调用存储过程 调用存储过程 call p1(1,5,@res);
五、开发三种模型(了解)
①程序员就写程序,DBA帮你写所有sql语句
应用程序:只需要开发应用程序的逻辑
mysql:编写好存储过程,以供应用程序调用
优点:开发效率,执行效率都高
缺点:考虑到人为因素、跨部门沟通等问题,会导致扩展性差
②程序和sql全都自己写
应用程序:除了开发应用程序的逻辑,还需要编写原生sql
优点:比方式1,扩展性高(非技术性的)
缺点: 开发效率,执行效率都不如方式1 编写原生sql太过于复杂,而且需要考虑到sql语句的优化问题
③程序员写程序,调用别人封装好的操作数据库的方法
应用程序:开发应用程序的逻辑,不需要编写原生sql,基于别人编写好的框架来处理数据,ORM
优点:不用再编写纯生sql,这意味着开发效率比方式2高,同时兼容方式2扩展性高的好处
缺点:执行效率连方式2都比不过
六、python代码调用储存过程
import pymysql conn = pymysql.connect( host='127.0.0.1', port=3306, user='root', password='3822515', database='day41', charset='utf8', autocommit=True ) cursor = conn.cursor(pymysql.cursors.DictCursor) cursor.callproc('p1', (1, 5, 10)) # @_p1_2 = 1 @_p1_1 = 5 @_p1_2 = 10 cursor.execute('select @_p1_2') print(cursor.fetchall()) # [{'@_p1_2': 0}]
六、函数
1、注意与存储过程的区别,mysql内置的函数只能在sql语句中使用!
2、案例
create table blog( id int primary key auto_increment, name char(32), sub_time datetime ); insert into blog(name,sub_time) values ('第1篇','2015-03-01 11:31:21'), ('第2篇','2015-03-11 16:31:21'), ('第3篇','2016-07-01 10:21:31'), ('第4篇','2016-07-22 09:23:21'), ('第5篇','2016-07-23 10:11:11'), ('第6篇','2016-07-25 11:21:31'), ('第7篇','2017-03-01 15:33:21'), ('第8篇','2017-03-01 17:32:21'), ('第9篇','2017-03-01 18:31:21'); 格式化日期取出年月,然后按日期分组 select date_format(sub_time,'%Y-%m'),count(id) from blog group by date_format(sub_time,'%Y-%m');
七、流程控制
1、if条件语句 delimiter $$ create procedure proc_if () begin declare i int default 0; if i = 1 then select 1; elseif i = 2 then select 2; else select 7; end if; end $$ delimiter ; 2、while循环 delimiter $$ create procedure proc_while () begin declare num int ; set num = 0 ; while num < 10 do select num ; set num = num + 1 ; end while ; end $$ delimiter ;
八、索引与慢查询优化
1、知识回顾:数据都是存在硬盘上的,那查询数据不可避免的需要进行IO操作
2、索引在MySQL中也叫做“键”,是存储引擎用于快速找到记录的一种数据结构。 primary key unique key index key
①注意foreign key不是用来加速查询用的,不在我们研究范围之内,上面三种key前两种除了有加速查询的效果之外还有额外的约束条件 (primary key:非空且唯一,unique key:唯一),而index key没有任何约束功能只会帮你加速查询
②索引就是一种数据结构,类似于书的目录。意味着以后再查数据应该先找目录再找数据,而不是用翻页的方式查询数据
③本质都是:通过不断地缩小想要获取数据的范围来筛选出最终想要的结果,同时把随机的事件变成顺序的事件, 也就是说,有了这种索引机制,我们可以总是用同一种查找方式来锁定数据。
3、索引的影响:
在表中有大量数据的前提下,创建索引速度会很慢 在索引创建完毕后,对表的查询性能会大幅度提升,但是写的性能会降低
4、b+树
<https://images2017.cnblogs.com/blog/1036857/201709/1036857-20170912011123500-158121126.png>
①只有叶子结点存放真实数据,根和树枝节点存的仅仅是虚拟数据
②查询次数由树的层级决定,层级越低次数越少
③一个磁盘块儿的大小是一定的,那也就意味着能存的数据量是一定的。 如何保证树的层级最低呢?一个磁盘块儿存放占用空间比较小的数据项
④思考:我们应该给我们一张表里面的什么字段字段建立索引能够降低树的层级高度>>> 主键id字段
5、聚集索引(primary key)
聚集索引其实指的就是表的主键,innodb引擎规定一张表中必须要有主键。先来回顾一下存储引擎。
①myisam在建表的时候对应到硬盘有几个文件(三个)
②innodb在建表的时候对应到硬盘有几个文件(两个)frm文件只存放表结构,不可能放索引, 也就意味着innodb的索引跟数据都放在idb表数据文件中。
③特点:叶子结点放的一条条完整的记录
6、辅助索引(unique,index)
①辅助索引:查询数据的时候不可能都是用id作为筛选条件,也可能会用name,password等字段信息, 那么这个时候就无法利用到聚集索引的加速查询效果。就需要给其他字段建立索引,这些索引就叫辅助索引
②特点:叶子结点存放的是辅助索引字段对应的那条记录的主键的值 (比如:按照name字段创建索引,那么叶子节点存放的是:{name对应的值:name所在的那条记录的主键值})
③select name from user where name='jason';
上述语句叫覆盖索引:只在辅助索引的叶子节点中就已经找到了所有我们想要的数据
④select age from user where name='jason';
上述语句叫非覆盖索引,虽然查询的时候命中了索引字段name,但是要查的是age字段,所以还需要利用主键才去查找
测试索引
1. 准备表 create table s1( id int, name varchar(20), gender char(6), email varchar(50) ); 2、创建存储过程,实现批量插入记录 delimiter $$ create procedure auto_insert1() begin declare i int default 1; while(i<3000000)do insert into s1 values(i,'jason','male',concat('jason',i,'@oldboy')); set i=i+1; end while; end $$ delimiter; 3、调用存储过程 call auto_insert1(); 查看插了多少 select count(id) from s1; 4、查看存储过程 show create procedure auto_insert1G;