day07 MySQL索引事务


day07 MySQL索引事务

昨日内容回顾

pymysql模块

# 链接数据库都是使用这个模块的

# 创建链接
import pymysql
conn = pymysql.connect(
	host='127.0.0.1',
    port=3306,
    user='root',
    password='123',
    database='db1',
    charset='utf8',
    autocommit=True
)
# 生成一个游标对象
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

sql注入问题

sql注入问题:利用特殊符号的组合产生具有一定特殊含义的数据从而避免常规逻辑
核心就是敏感型数据不要自己去做拼接
	# execute方法可以帮SQL语句移除特殊符号的影响
    execute(sql,(%s,%s)) # 拼接username,password

今日内容概要

  • 视图
  • 触发器
  • 流程控制
  • 内置函数
  • 事务(重点记)
  • 索引
    • 二叉树
    • b树
    • b+树
    • b*树
    • 慢查询优化(explain语句)

视图view

# 优点:
	将SQL语句的查询结果当做虚拟表实体化保存下来,以后可以反复使用
# 缺点:
	1.只能当做查询使用,不能修删改。因为虚拟表自己是没有表数据的,数据是查询原表的
	2.虽然视图没有表数据文件,但是也有一个表结构文件。建太多也会占内存。
	3.在cmd中查看表,虚拟表看起来和普通表一样,但是当修改时候容易混淆。
	
# 格式:
	create view 视图名 as SQL语句
	
	mysql> create view s1 as select * from course inner join teacher on course.teacher_id=teacher.tid;

触发器trigger

触发器:在满足对某张表数据的增、删、改的情况下,自动触发的功能称之为触发器
1、触发器:满足特定条件之后自动执行
在MySQL只有三种情况下触发
	1.针对表的增
		# 增前、增后:会触发条件执行
	2.针对表的改
		# 改前、改后:会触发条件执行
	3.针对表的删
		# 删前、删后:会触发条件执行
		
2、为什么用触发器
	触发器专门针对我们对某一张表数据进行增insert、删delete、改update的行为,这类行为一旦执行,
	就会触发触发器的执行,即自动运行另外一段SQL代码
	
3、语法结构
    create trigger 触发器的名字 before/after insert/update/delete on 表名 for each row
    begin
        sql语句
    end
    # 想要使用触发器的前提是把结束符换掉

# 触发器名字在命名的时候推荐使用下列的方式
	tri_after_insert_t1、tri_before_delete_t1   # 见名知意:在对t1表插入之前触发,t1表删除之后触发
	
# 如何临时修改SQL语句的结束符(使用触发器的前提换掉结束符)
	delimiter $$   # 以前结束符是 ;

# 在MySQL中NEW特指数据对象可以通过点的方式获取字段对应的数据
	id    name	pwd  hobby
	1     jason  123  read
	NEW.name  >>>  jason
	
4、案例
1.创建表
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代表执行失败
);

2.创建错误日志表
CREATE TABLE errlog (
id INT PRIMARY KEY auto_increment,
err_cmd CHAR (64),
err_time datetime
);

3.创建触发器(模板)
delimiter $$  # 将mysql默认的结束符由;换成$$
create trigger tri_after_insert_cmd after insert on cmd for each row
begin
if NEW.success = 'no' then  # 新记录都会被MySQL封装成NEW对象
insert into errlog(err_cmd,err_time) values(NEW.cmd,NEW.sub_time);
end if;
end $$
delimiter ;  # 结束之后记得再改回来,不然后面结束符就都是$$了


4.往表cmd中插入记录,触发触发器,根据IF的条件决定是否插入错误日志
INSERT INTO cmd (
    USER,
    priv,
    cmd,
    sub_time,
    success
)
VALUES
    ('tony','0755','ls -l /etc',NOW(),'yes'),
    ('tony','0755','cat /etc/passwd',NOW(),'no'),
    ('tony','0755','useradd xxx',NOW(),'no'),
    ('tony','0755','ps aux',NOW(),'yes');

# 查询errlog表记录
select * from errlog;
# 查看触发器
show triggers;  # \G:会格式化
# 删除触发器
drop trigger tri_after_insert_cmd;

事务

事务四大特性(ACID)
	A:原子性
		每个事务都是不可分割的最小单位(同一个事务内的多个操作要么是同时成功,要么同时失败)
		
	C:一致性
		事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
		
	I:隔离性
		事务与事务之间彼此互不干扰。  # 高并发时候会出现
		
	D:持久性
		一个事务一旦提交,它对数据库中数据的改变就应该是永久性。
		
# 开启事务
	start transaction;
	
# 回滚到上一个状态
	rollback;
	
# 确认事务
	commit;
	# 事务在没有确认之前,数据是保存在内存中临时修改下,一旦确认了会保存在硬盘中并且回滚不了。

存储过程

存储过程:类似于python中的自定义函数。用过调用它的名字可以执行其内部的SQL语句。

用法:
    1.查看存储过程具体信息
        show create procedure p2;
    2.查看所有存储过程
        show procedure status;
    3.删除存储过程
        drop procedure p2;

1、无参存储过程
    delimiter $$
    create procedure p1()
    begin
        select * from user;
    end $$
    delimiter ;
    
# 调用
    call p1()

2、有参存储过程
1.创建存储过程(模板)
    delimiter $$
    create procedure p2(
        in m int,  # in表示这个参数必须只能是传入不能被返回出去
        in n int,  
        out res int  # out表示这个参数可以被返回出去,还有一个inout表示即可以传入也可以被返回出去
    )
    begin
        select * from teacher where tid > m and tid < n;
        set res=0;  # 用来标志存储过程是否执行
    end $$
    delimiter ;

2.针对res需要提前定义
    set @res=10;  定义
    select @res;  查看
    call p2(1,5,@res);  调用


3.代码操作存储过程
    import pymysql
    conn = pymysql.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        passwd='123',
        db='db6',
        charset='utf8',
        autocommit=True
    )
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.callproc('p2',(1,3,10))   # 存储过程
    # @_p1_0=1,@_p1_1=3,@_p1_2=10;
    print(cursor.fetchall())	

函数

# 相当于Python中的内置函数
函数和存储过程的区别:MySQL内置函数只能在SQL语句中使用
'''可以通过hele 函数名,查看帮助信息'''

1、移除指定字符
Trim、LTrim、RTrim

2、大小写转换
Lower、Upper

3、获取左右起始指定个数字符
Left、Right

4、返回读音相似值(对英文效果)
Soundex
"""
eg:客户表中有一个顾客登记的用户名为J.Lee
		但如果这是输入错误真名其实叫J.Lie,可以使用soundex匹配发音类似的
		where Soundex(name)=Soundex('J.Lie')
"""

5、日期格式:date_format
'''在MySQL中表示时间格式尽量采用2022-11-11形式'''
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.where Date(sub_time) = '2015-03-01'
2.where Year(sub_time)=2016 AND Month(sub_time)=07;
# 更多日期处理相关函数 
	adddate	增加一个日期 
	addtime	增加一个时间
	datediff计算两个日期差值
  ...

流程控制

# if判断
if i = 1 THEN
       SELECT 1;
ELSEIF i = 2 THEN
       SELECT 2;
ELSE
       SELECT 7;
END IF;

# while循环
SET num = 0 ;
WHILE num < 10 DO
    SELECT
        num ;
    SET num = num + 1 ;
END WHILE ;

索引与慢查询优化(重点)

索引:简单的理解为可以帮助你加快数据查询速度的工具
	# 索引相当于书的目录

1、算法:解决事务的办法
	入门级算法:二分法
    二分法的前提:数据集必须是有序的
    nums = [-3, 5, 7, 11, 21, 31, 41, 53, 67, 77, 83, 99, 101]

def search(nums,find_num):
    print(nums)
    if len(nums)  == 0:
        print('不存在')
        return
    mid_index = len(nums) // 2
    if find_num > nums[mid_index]:
        # 在右半部分
        search(nums[mid_index+1:],find_num)
    elif find_num < nums[mid_index]:
        # 在左半部分
        search(nums[:mid_index],find_num)
    else:
        print('找到了')
# search(nums,67)
search(nums,69)
# 二分法理论:在数据中间切一半对比,判断69在哪一半里,在切一半判断一直找到这个数为止。

2、数据结构
	二叉树:(只能分两个叉)
	b树 b+树(叶子节点添加了指针) b*树(枝节点也添加了指针)
    # 添加指针是为了加快范围查询的速度
    # 精准查找:使用b树,范围查找:b+树
 
将某个字段添加成索引就相当于依据该字段建立了一颗b+树从而加快查询速度
如果某个字段没有添加索引 那么依据该字段查询数据会非常的慢(一行行查找)
# 结论:查询速度特别慢,应该建索引。 name  age 之类的

B+tree索引

索引的分类

1、primary key
	主键索引:除了有加速查询的效果外,还具有一定的约束条件
	
2、unique key
	唯一键索引:除了有加速查询的效果外,还具有一定的约束条件
	
3、index key
	普通索引:只有加速查询的效果,没有额外约束条件

数据库设计三大范式

什么是范式:
	为了建立冗余较小、结构合理的数据库,设计数据库时必须遵循一定的规则。在关系型数据库中这种规则就称为范式。
    
第一范式(确保每列都保持原子型)
	第一范式是最基本的范式。如果数据库表中的所有字段之都是不可分解的原子值吗,就说明该数据库表满足了第一范式。
    
第二范式(确保表中的每列都和主键相关)
	第二范式在第一范式的基础之上更进一层。第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关。
    
第三范式(确保每列都和主键列直接相关,而不是间接相关)
	第三范式需要确保数据表中的每一列数据都和主键直接相关,而不是间接相关。