一、视图
1、简介:视图就是通过查询得到虚拟表的实体化,保存于硬盘,下次或其他窗口也可以使用。
2、用途:若一份虚拟表需要重复使用,可以考虑使用视图来简化后续操作。
3、注意:
①视图虽然也是存于硬盘的表,但是该表只有表结构,没有表数据,上面显示的数据还是来自于查询目标的表。
②视图一般只用来再查询,最好不要修改里面的数据,以防影响原表。
③视图最好不要过多创建,以免增加维护难度。
4、基本语法:create view 视图名 as 查询语句
二、触发器
1、简介:触发器就是绑定某表的某项操作(增/删/改)之前或结束能自动触发定义好功能的机制,一般用于监控或记录日志等。
2、基本语法:create trigger 触发器名 before/after insert/update/delete on 表名 for each row begin 触发语句 end
3、delimiter:用于修改sql语句的默认结束符,如,delimiter $$---将默认结束符“;”改为了“$$”。
4、实例:
CREATE TABLE cmd ( id INT PRIMARY KEY auto_increment, USER CHAR (32), priv CHAR (10), cmd CHAR (64), sub_time datetime, #提交时间 success enum ('yes', 'no') #0代表执行失败 ); CREATE TABLE errlog ( id INT PRIMARY KEY auto_increment, err_cmd CHAR (64), err_time datetime ); """ 当cmd表中的记录succes字段是no那么就触发触发器的执行去errlog表中插入数据 NEW指代的就是一条条数据对象 """ delimiter $$ 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 ; # 朝cmd表插入数据 INSERT INTO cmd ( USER, priv, cmd, sub_time, success ) VALUES ('jason','0755','ls -l /etc',NOW(),'yes'), ('jason','0755','cat /etc/passwd',NOW(),'no'), ('jason','0755','useradd xxx',NOW(),'no'), ('jason','0755','ps aux',NOW(),'yes'); # 删除触发器 drop trigger tri_after_insert_cmd;
三、事务
1、简介:事务就是把多条需要同时执行的sql语句绑定成组合的机制,组合中的sql语句要么同时成功,要么同时失败,以此确保数据操作的完整性。
2、特性:
①原子性:一个事务中的多条sql语句相互是无可分割的。
②一致性:一个事务中的多条sql语句必定是同时执行,同时成功或同时失败。
③隔离性:一个事务执行的过程中不会被其他事务干扰,类似于并发程序的互斥锁,并发事务对数据的操作也是互不干扰的。
④持久性:一个事务一旦执行成功,其执行结果会立即生效,硬盘上的数据则立刻被执行了相应的修改,这个操作是永久的,而非临时性的,且不可回撤。
3、rollback:回滚,事务开启后,无论已经执行了多少条sql语句,一旦遇到回滚,则立即回到事务开启前的状态。
4、commit:确认,确认之后则无法再使用回滚,相当于事务真正执行结束了。
3、基本语法:start transaction;sql语句1; sql语句2; rollback; sql语句3;sql语句4; commit
四、存储过程
1、简介:存储过程就是把一系列的sql语句整合成了一个存储过程名,调用这个存储过程即执行了这些sql语句,类似于自定义函数。
2、基本语法:
①定义存储过程:create procedure 存储过程名(形参1,形参2) begin sql语句1; sql语句2; end
②调用存储过程:call 存储过程名(实参1,实参2)
3、三种开发模式:
①数据库管理员提前编写好存储过程,应用程序员直接调用到应用程序代码中。
优点:节省了应用程序员编写存储过程的时间,提高了开发效率,用已封装好的存储过程执行复杂的sql语句,提高了执行效率。
缺点:因为存在不同部门之间的沟通问题,后续的可拓展性比较差。
②应用程序员自己根据开发需求直接编写存储过程。
优点:自己动手,丰衣足食,拓展性极佳。
缺点:编写存储过程比较繁琐,后期还需要自己优化,降低了开发效率。
③应用程序员基于别人已经写好的数据库框架直接套用,如ORM框架。
优点:不用自己编写存储过程,套用灵活性更高的框架,开发效率更高。
缺点:框架的语句有时有所局限,此时还需要回到上述两种途径解决。
④小结:当前的主流几乎不再用第一种,大多是以第三种为主,出现特殊情况再临时用第二种手动编写。
4、实例:
delimiter $$ create procedure p1( in m int, # 只进不出 m不能返回出去 in n int, out res int # 该形参可以返回出去 ) begin select tname from teacher where tid>m and tid<n; set res=666; # 将res变量修改 用来标识当前的存储过程代码确实执行了 end $$ delimiter ; # 针对形参res 不能直接传数据 应该传一个变量名 # 定义变量 set @ret = 10; # 查看变量对应的值 select @ret;
5、python中调用存储过程:
import pymysql conn = pymysql.connect( host = '127.0.0.1', port = 3306, user = 'root', passwd = '123456', db = 'day48', charset = 'utf8', autocommit = True ) cursor = conn.cursor(pymysql.cursors.DictCursor) # 调用存储过程 cursor.callproc('p1',(1,5,10)) """ @_p1_0=1 @_p1_1=5 @_p1_2=10 """ # print(cursor.fetchall()) cursor.execute('select @_p1_2;') print(cursor.fetchall())
五、函数
1、简介:函数就是内置的存储过程,类似于内置函数。
2、实例:
('jason','0755','ls -l /etc',NOW(),'yes') 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、简介:语法比python要复杂。
2、实例:
# 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 ; # 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 ;
七、索引
1、简介:索引是数据存于硬盘中的标识,类似于书籍的目录,查询数据时,先通过查找索引定位好数据所在,之后再直接读取,以此可以提高IO效率,所以索引也就代表了数据的结构。
2、分类:索引也叫“键”,不同的“键”对应着不同的数据结构。
①primary key:主键结构,除了提升查询效率,还有唯一且非零的约束,并且一张表只能有一个主键。
②unique key:唯一键结构,除了提升查询效率,还有唯一的约束。
③index key:标识键结构,没有任何约束,只是用来提升查询效率。
3、作用:通过不断缩小数据查找范围达到最终结果,将无序查找变为了有序查找。
4、多索引并存:一张表中可以有多个索引,根据筛选条件匹配相应的索引。
5、索引的弊端:当表中有大量数据存在的前提下,创建索引的速度会很慢,创建完索引,虽然查询效率会大幅提升,但是由于需要有序写入,所以写入的效率会大幅降低。
6、小结:索引应该结合实际需求谨慎创建。
7、b+树:只有最下层的叶子节点存放的是真实数据,其他节点存放的都是虚拟数据,仅用来分区,树的层级越多,查询数据所需经历的步骤也就越多,基于此,因为一个磁盘的存储容量是有限的,将id字段作为索引,因为其是数字占用空间比较小,所以一个磁盘就能够存储多个id字段的索引,从而可以减少树的层数,进而减少查询步骤,也就提高了查询效率。
8、聚集索引:也就是primary key主键,innodb中只有两个文件,把索引并放在了ibd表中,而myisam中有三个文件,其中有一个专门存放索引的文件。
9、辅助索引:即unique key主键与index key标识键,查询数据的时候有时不会根据主键筛选,此时便无法使用主键的聚集索引,而使用其他字段的辅助索引,无论是聚集索引还是辅助索引,都是b+树的形式,区别在于,聚集索引的叶子节点就是目标数据,而辅助索引的叶子节点是主键的值,拿到主键的值之后还需要再基于聚集索引找到目标数据。
10、覆盖索引:使用辅助索引时,筛选条件即目标数据。
# 给name设置辅助索引 select name from user where name='jason'; # 非覆盖索引 select age from user where name='jason';
11、测试索引代码:
**准备** ```mysql #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. 查看存储过程 show create procedure auto_insert1\G #4. 调用存储过程 call auto_insert1(); ``` ``` mysql # 表没有任何索引的情况下 select * from s1 where id=30000; # 避免打印带来的时间损耗 select count(id) from s1 where id = 30000; select count(id) from s1 where id = 1; # 给id做一个主键 alter table s1 add primary key(id); # 速度很慢 select count(id) from s1 where id = 1; # 速度相较于未建索引之前两者差着数量级 select count(id) from s1 where name = 'jason' # 速度仍然很慢 """ 范围问题 """ # 并不是加了索引,以后查询的时候按照这个字段速度就一定快 select count(id) from s1 where id > 1; # 速度相较于id = 1慢了很多 select count(id) from s1 where id >1 and id < 3; select count(id) from s1 where id > 1 and id < 10000; select count(id) from s1 where id != 3; alter table s1 drop primary key; # 删除主键 单独再来研究name字段 select count(id) from s1 where name = 'jason'; # 又慢了 create index idx_name on s1(name); # 给s1表的name字段创建索引 select count(id) from s1 where name = 'jason' # 仍然很慢!!! """ 再来看b+树的原理,数据需要区分度比较高,而我们这张表全是jason,根本无法区分 那这个树其实就建成了“一根棍子” """ select count(id) from s1 where name = 'xxx'; # 这个会很快,我就是一根棍,第一个不匹配直接不需要再往下走了 select count(id) from s1 where name like 'xxx'; select count(id) from s1 where name like 'xxx%'; select count(id) from s1 where name like '%xxx'; # 慢 最左匹配特性 # 区分度低的字段不能建索引 drop index idx_name on s1; # 给id字段建普通的索引 create index idx_id on s1(id); select count(id) from s1 where id = 3; # 快了 select count(id) from s1 where id*12 = 3; # 慢了 索引的字段一定不要参与计算 drop index idx_id on s1; select count(id) from s1 where name='jason' and gender = 'male' and id = 3 and email = 'xxx'; # 针对上面这种连续多个and的操作,mysql会从左到右先找区分度比较高的索引字段,先将整体范围降下来再去比较其他条件 create index idx_name on s1(name); select count(id) from s1 where name='jason' and gender = 'male' and id = 3 and email = 'xxx'; # 并没有加速 drop index idx_name on s1; # 给name,gender这种区分度不高的字段加上索引并不难加快查询速度 create index idx_id on s1(id); select count(id) from s1 where name='jason' and gender = 'male' and id = 3 and email = 'xxx'; # 快了 先通过id已经讲数据快速锁定成了一条了 select count(id) from s1 where name='jason' and gender = 'male' and id > 3 and email = 'xxx'; # 慢了 基于id查出来的数据仍然很多,然后还要去比较其他字段 drop index idx_id on s1 create index idx_email on s1(email); select count(id) from s1 where name='jason' and gender = 'male' and id > 3 and email = 'xxx'; # 快 通过email字段一剑封喉 ``` #### 联合索引 ```mysql select count(id) from s1 where name='jason' and gender = 'male' and id > 3 and email = 'xxx'; # 如果上述四个字段区分度都很高,那给谁建都能加速查询 # 给email加然而不用email字段 select count(id) from s1 where name='jason' and gender = 'male' and id > 3; # 给name加然而不用name字段 select count(id) from s1 where gender = 'male' and id > 3; # 给gender加然而不用gender字段 select count(id) from s1 where id > 3; # 带来的问题是所有的字段都建了索引然而都没有用到,还需要花费四次建立的时间 create index idx_all on s1(email,name,gender,id); # 最左匹配原则,区分度高的往左放 select count(id) from s1 where name='jason' and gender = 'male' and id > 3 and email = 'xxx'; # 速度变快 ```