Day25-MySQL上


title: Day25-MySQL上
date: 2020-08-12 13:55:49
author: 子陌


MySQL - 上

  • 启动:service mysql start
  • 停止:service mysql stop
  • 登录:mysql -u root -p 123456
  • 设置当前用户登录的密码:set password = password(‘123456’);
  • 授权远程登录:grant all privileges on *.* to 'root'@'%' indentified by '123456'
    • 刷新授权:flush privileges
  • 查看防火墙:service iptables status
    • 关闭防火墙:service iptables stop

索引

索引概述

索引是帮助MySQL高效查询数据结构

索引

索引优势和劣势

  • 优势

    1 ) 类似于书籍的目录索引,提高数据检索的效率,降低数据库的IO成本。

    2 ) 通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗。

  • 劣势
    1 ) 实际上索引也是一张表,该表中保存了主键与索引字段,并指向实体类的记录,所以索引列也是要占用空间的。
    2 ) 虽然索引大大提高了查询效率,同时却也降低更新表的速度,如对表进行INSERT、UPDATE、 DELETE。因为更新表时,,MySQL不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息。

索引结构

索引是在MySQL的存储引擎层中实现的,而不是在服务器层实现的。所以每种存储引擎的索引都不一定完全相同,也不是所有的存储引擎都支持所有的索引类型的。MySQL目前提供了以下4种索引:

  • BTREE索引:最常见的索引类型,大部分索引都支持B树索引
  • HASH索引:只有Memory引擎支持,使用场景简单
  • R-tree(空间索引):空间索引是MyISAM引擎的一个特殊索引类型,主要用于地理空间数据类型,通常使用较少
  • Full-text(全文索引):全文索引也是MyISAM的一个特殊索引类型,主要用于全文索引,InnoDB从Mysql5.6版本开始支持全文索引。
索引 InnoDB引擎 MyISAM引擎 Memory引擎
BTREE索引 支持 支持 支持
HASH索引 不支持 不支持 支持
R-tree索引 不支持 支持 不支持
Full-text索引 Version 5.6后支持 支持 不支持
MyISAM、InnoDB、Memory三种存储引擎对各种索引类型的支持

我们平常所说的索引,如果没有特别指明,都是指B+树(多路搜索树,并不一定是二叉的)结构组织的索引。其中聚集索引、复合索引、前缀索引、唯一索引默认都是使用B+tree树索引,统称为索引。

BTREE结构

BTree又叫多路平衡搜索树,一颗m叉的BTree特性如下:

  • 树中每个节点最多包含m个孩子。
  • 除根节点与叶子节点外,每个节点至少有[ceil(m/2)]个孩子。
  • 若根节点不是叶子节点,则至少有两个孩子。
  • 所有的叶子节点都在同一层。
  • 每个非叶子节点由n个key与n+1个指针组成,其中[ceil(m/2)-1]<=n<=m-1
  • 例如:如果是5叉叶子节点2 <= m <= 4,超过4,则向上分裂

BTree分裂过程

BTREE树构建完成了,BTREE树 和二叉树相比,查询数据的效率更高,因为对于相同的数据量来说,BTREE的层级结构比二叉树小,因此搜索速度快。

B+TREE结构
  • B+Tree为BTree的变种,B+Tree与BTree的区别为:

    1 ) n叉B+Tree最多含有n个key,而BTree最多含有n-1个key。
    2 ) B+Tree的叶子节点保存所有的key信息,依key大小顺序排列。
    3 ) 所有的非叶子节点都可以看作是key的索引部分。

B+树数据结构

MySQL中的B+Tree

MySq|索引数据结构对经典的B+Tree进行了优化。在原B+Tree的基础上,增加一个指向相邻叶子节点的链表指针,就形成了带有顺序指针的B+Tree,提高区间访问的性能。
MySQL中的B+Tree 索引结构示意图:

MySQL中B+树

索引分类

  1. 单值索引:即一个索引只包含单个列,一个表可以有多个单列索引
  2. 唯一索引:索引列的值必须唯一,但允许有空值
  3. 复合索引:即一个索引包含多个列

索引语法

  • 创建索引:CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name [USING index_type] ON tbl_name(index_col_name,...)

    create [索引类型] INDEX 索引名称 [索引类型:默认B+树] ON 表名(字段名)

  • 查看索引:show index for table_name

  • 删除索引:DROP INDEX index_name ON tbl_name

  • ALERT命令:

    • alter table tb_name add primary key(column_list)

      该语句添加一个主键,这意味着索引值必须是唯一的,且不能为NULL

    • alter table ta_name add unique index_name(column_list)

      这条语句创建索引的值必须是唯一的(除了NULL外,NULL可能会出现多次)

    • alter table tb_name add index index_name(column_list)

      添加普通索引,索引值可以出现多次

    • alter table tb_name add fulltext index_name(column_list)

      该语句指定了索引为FULLTEXT,用于全文索引

索引设计原则

索引的设计可以遵循一些已有的原则,创建索引的时候请尽量考虑符合这些原则,便于提升索引的使用效率,更高效的使用索引。

  • 对查询频次较高,且数据量比较大的表建立索引。
  • 索引字段的选择,最佳候选列应当从where子句的条件中提取,如果where子句中的组合比较多,那么应当挑选最常用、过滤效果最好的列的组合。
  • 使用唯一索引,区分度越高,使用索引的效率越高。
  • 索引可以有效的提升查询数据的效率,但索引数量不是多多益善,索引越多,维护索引的代价自然也就水涨船高。对于插入、更新、删除等DML操作比较频繁的表来说,索引过多,会引入相当高的维护代价,降低DML操作的效率,增加相应操作的时间消耗。另外索引过多的话,MySQL也会犯选择困难病,虽然最终仍然会找到一个可用的索引,但无疑提高了选择的代价。
  • 使用短索引,索引创建之后也是使用硬盘来存储的,因此提升索引访问的I/O效率,也可以提升总体的访问效率。假如构成索引的字段总长度比较短,那么在给定大小的存储块内可以存储更多的索引值,相应的可以有效的提升MySQL访问索引的I/O效率。
  • 利用最左前缀,N个列组合而成的组合索引,那么相当于是创建了N个索引,如果查询时where子句中使用了组成该索引的前几个字段,那么这条查询SQL可以利用组合索引来提升查询效率。
-- 创建复合索引
	CREATE INDEX idx_name_email_status ON tb_seller(name, email, status);
-- 相当于
	* 对name 创建了索引
	* 对name, email 创建了索引
	* 对name, email, status 创建了索引

视图

视图概述

视图(View)是一种虚拟存在的表。视图并不在数据库中实际存在,行和列数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的。通俗的讲,视图就是一条SELECT语句执行后返回的结果集。所以我们在创建视图的时候,主要的工作就落在创建这条SQL查询语句上。视图相对于普通的表的优势主要包括以下几项。

  • 简单:使用视图的用户完全不需要关心后面对应的表的结构、关联条件和筛选条件,对用户来说已经是过滤好的复合条件的结果集。
  • 安全:使用视图的用户只能访问他们被允许查询的结果集,对表的权限管理并不能限制到某个行某个列,但是通过视图就可以简单的实现。
  • 数据独立:一旦视图的结构确定了,可以屏蔽表结构变化对用户的影响,源表增加列对视图没有影响;源表修改列名,则可以通过修改视图来解决,不会造成对访问者的影响。

视图创建和修改

  • 创建视图语法
CREATE [OR REPLACE] [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
VIEW view_name[(column_list)]
AS select_statement -- select语句
[WITH [CASCADED | LOCAL] CHECK OPTION]
  • 修改视图语法
ALTER [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
VIEW view_name[(column_list)]
AS select_statement -- select语句
[WITH [CASCADED | LOCAL] CHECK OPTION]
-- 选项:
	WITH [CASCADED | LOCAL] CHECK OPTION -- 决定了是否允许更新数据使记录不再满足视图的条件
	
	LOCAL:只要满足本是图的条件就可以更新
	CASCADED

视图查看和删除

  • 查看视图语法
show tables		-- 查看视图 mysql 5.1开始使用
show create view view_name;	-- 查看创建视图时的语句
  • 删除视图语法
DROP view [IF EXISTS] view_name [, view_name] ...[RESTRICT | CASCADE]
-- eg:
	DROP view view_city_country

存储过程和函数

存储过程和函数概念

存储过程和函数是事先经过编译并存储在数据库中的一段SQL语句的集合,调用存储过程和函数可以简化应用开发人员的很多工作,减少数据在数据库和应用服务器之间的传输,对于提高数据处理的效率是有好处的。

存储过程和函数的区别在于函数必须有返回值,而存储过程没有。

  • 函数:是一个有返回值的过程;
  • 过程:是一个没有返回值的函数;

创建存储过程

CREATE PROCEDURE procedure_name([proc_parameter[,...]])
begin
	-- SQL语句
end ;

--eg:
delimiter $		-- 替换分隔符

create procedure pro_test1()
begin
	select 'hello mysql';
end$

delimiter ; 
  • DELIMITER

    该关键字用来声明SQL语句的分隔符,告诉MySQL解释器,该段命令是否已经结束了,mysq|是否可以执行了。默认情况下,delimiter是分号。在命令行客户端中,如果有一行命令以分号结束,那么回车后,mysq|将会执行该命令。

调用存储过程

call pro_test1();

查看存储过程

-- 查询db_name数据库中的所有的存储过程 mysql数据库中proc表存储着所有数据库的存储过程信息
select name from mysql.proc where db = 'db_name';

-- 查询存储过程的状态信息
show procedure status;

-- 查询某个存储过程的定义
show create procedure test.pro_test1 \G;

删除存储过程

DROP PROCEDURE [IF EXTSTS] sp_name

存储过程语法

  • DECLARE

    通过DECLARE可以定义一个局部变量,该变量的作用范围只能在BEGIN…END块中

    DECLARE var_name[,...] type [DEFAULT value]

    delimiter $
    create procedure pro_test2()
    begin
    	declare num int default 5;
    	select num + 10;
    end$
    delimiter ;
    
  • SET

    直接赋值使用SET,可以赋常量或者表达式

    SET var_name = expr [, var_name = expr]...

    delimiter $
    create procedure pro_test4()
    begin
    	declare name varchar(20);
    	set name = 'mysql';
    	select name;
    end$
    delimiter ;
    

    也可以通过select…into方式进行赋值操作

    delimiter $
    create procedure pro_test4()
    begin
    	declare countnum int;
    	select count(*) into countnum from city;	-- 将查询到的值赋值给countnum
    	select countnum;
    end$
    delimiter ;
    
  • if条件判断

    # 语法格式:
    if serch_condition then statement_list
    	[elseif serch_condition then statement_list]...
    	[else statement_list]
    end if;
    
    # 需求:
    # 	180+		: 高挑
    # 	170-180		:标准
    # 	170-		:一般 
    delimiter $
    create procedure pro_test5()
    begin
    	declare height int default 176;
    	declare description varchar(50);
    	if height >= 180 then 
    		set description = '身材高挑';
    	elseif height >= 170 and height < 180 then
    		set description = '身材标准';
    	else
    		set description = '身材一般';
    	end if;
    	select concat('身高:',height,' 对应类型:',description)
    end$
    delimiter ;
    
  • 输入参数

    # 语法格式:
    create procedure procedure_name([in/out/inout] 参数名  参数类型)
    in 		-- 该参数可以作为输入,也就是需要调用方传入值,默认
    out 	-- 该参数可以作为输出,也就是该参数可以作为返回值
    inout 	-- 既可以输入,也可以输出
    # 需求:
    # 	180+		: 高挑
    # 	170-180		:标准
    # 	170-		:一般 
    delimiter $
    create procedure pro_test5_in(in height int)
    begin
    	declare description varchar(50);
    	if height >= 180 then 
    		set description = '身材高挑';
    	elseif height >= 170 and height < 180 then
    		set description = '身材标准';
    	else
    		set description = '身材一般';
    	end if;
    	select concat('身高:',height,' 对应类型:',description)
    end$
    
    # 调用格式:call pro_test5_out(178,@description)  select @description
    create procedure pro_test5_out(in height int, out description varchar(50))
    begin
    	if height >= 180 then 
    		set description = '身材高挑';
    	elseif height >= 170 and height < 180 then
    		set description = '身材标准';
    	else
    		set description = '身材一般';
    	end if;
    end$
    
    delimiter ;
    

    @description:这种变量要在变量名称前面加上"@“符号,叫做用户会话变量,代表整个会话过程他都是有作用的,这个类似于全局变量一样。
    @@global.sort_ buffer.size:这种在变量前加上”@@"符号,叫做系统变量

  • case结构

    # 方式一:
    CASE case_value
    	WHEN when_value THEN statement_list
    	[WHEN when_value THEN statement_list]...
    	[ELSE statement_list]
    END CASE;
    # 方式二:
    CASE
    	WHEN search_condition THEN statement_list
    	[WHEN search_condition THEN statement_list]...
    	[ELSE statement_list]
    END CASE;
    
    -- 案例:给定一个月份,然后计算出所在的季度
    delimiter $
    create procedure pro_test6(mon int)
    begin
    	declare result varchar(10);
    	case
    		when mon >=1 and mon <= 3 then
    			set result = '第一季度';
    		when mon >=4 and mon <= 6 then
    			set result = '第二季度';
    		when mon >=7 and mon <= 9 then
    			set result = '第三季度';
    		when mon >=10 and mon <= 12 then
    			set result = '第四季度';
    		ELSE
    			set result = '非法月份';
    	end case;
    end$
    delimiter ;
    
  • while循环

    # 语法结构
    while search_condition do
    	statement_list
    end while;
    
    -- 案例:1累加到n
    delimiter $
    create procedure pro_test7(n int)
    begin
    	declare total int default 0;
    	declare num int default 1;
    	while num <= n do
    		set total = total + num;
    		set num = num + 1;
    	end while;
    	select total;
    end$
    delimiter ;
    
  • repeat循环:有条件的循环控制语句,当满足条件的时候退出循环。while是满足条件才执行,repeat是满足条件就退出循环

    # 语法结构
    REPEAT
    	statement_list
    	UNTIL search_condition	-- 这里不能添加;
    END REPEAT;
    
    -- 案例:1累加到n
    delimiter $
    create procedure pro_test8(n int)
    begin
    	declare total int default 0;
    	repeat
    		set total = total + n;
    		set n = n - 1;
    		until n = 0
    	end repeat;
    	select total;
    end$
    delimiter ;
    
  • loop循环:loop实现简单的循环,退出循环的条件需要使用其他的语句定义,通常可以使用leave语句实现

    # 语法结构
    [begin_label:] LOOP
    	statement_list
    END LOOP [end_label];
    

    如果不在statement_list中增加退出循环的语句,那么LOOP语句可以用来实现简单的死循环

  • leave语句:用来从标注的流程构造中退出,通常和BEGIN…END或者循环一起使用。下面是一个使用LOOP和LEAVE的简单例子,退出循环

    delimiter $
    create procedure pro_test9(n int)
    begin
    	declare total int default 0;
    	ct: loop
    		set total = total + n;
    		set n = n - 1;
    		if n <= 0 then
    			leave ct;
    		end if;
    	end loop ct;
    	select total;
    end$
    delimiter ;
    
  • 游标/光标

    游标是用来存储查询结果集的数据类型,在存储过程和函数中可以使用光标对结果集进行循环的处理。光标的使用包括光标的声明、OPEN、FETCH和CLOSE,其语法分别如下。

    • 声明光标:

      DECLARE cursor_name CURSOR FOR select_statement

    • OPEN光标:

      OPEN cursor_name

    • FETCH光标:抓取游标数据,每抓一次往下走一行,类似于迭代器的next

      FETCH cursor_name INTO var_name [, var_name]...

    • CLOSE光标:

      CLOSE cursor_name

光标的使用

-- 案例:查询emp表中数据,并逐行获取进行展示
delimiter $
create procedure pro_test10(n int)
begin
	declare e_id int(11),	-- 这些字段必须和数据库中类型一致
	declare e_name varchar(50),	-- 这些字段必须和数据库中类型一致
	declare e_age int(11),	-- 这些字段必须和数据库中类型一致
	declare e_salary int(11),	-- 这些字段必须和数据库中类型一致
	declare has_data int default 1;
	
	declare emp_result cursor for select* from emp;	-- 声明一个游标
	DECLARE EXIT HANDLER FOR NOT FOUND set has_data = 0;
	

	# 开启游标
	open emp_result;
	# 获取数据
	repeat
		fetch emp_result into e_id, e_name, e_age, e_salary;	-- 和数据库中字段一致
		select concat(e_id, e_name, e_age, e_salary);
		
		until has_data = 0;
	end repeat;
	# 关闭游标
	close emp_result;
end$
delimiter ;

存储函数

  1. 调用存储函数:select function_name(param)
  2. 删除存储函数:drop function function_name
# 语法结构
CREATE FUNCTION function_name([param type ...])
RETURNS type
BEGIN
	...
END;
  • 案例:定义一个存储函数,获取满足条件的总记录数
delimiter $
create function fun1(countryId int)
RETURNS int
begin
	declare cnum int;
	select count(*) into cnum from city where country_id = countryId;
	return cnum;
end$
delimiter ;

## 函数调用
select fun1(1);

触发器

介绍

触发器是与表有关的数据库对象,指在insert/update/delete之前或之后,触发并执行触发器中定义的SQL语句集合。触发器的这种特性可以协助应用在数据库端确保数据的完整性,日志记录,数据校验等操作。

使用别名OLD和NEW来引用触发器中发生变化的记录内容,这与其他的数据库是相似的。现在触发器还只支持行级触发,不支持语句级触发。

触发器类型 NEW和OLD的使用
INSERT型触发器 NEW表示将要或者已经新增的数据
UPDATE型触发器 OLD表示修改之前的数据,NEW表示将要或已经修改后的数据
DELETE型触发器 OLD表示将要或者已经删除的数据

创建触发器

create trigger trigger_name		-- 创建一个trigger_name触发器
before / after   insert / update / delete	-- 在insert/update/delete 之前/之后执行
on tbl_name
[for each row]
trigger_stmt;
  • 通过触发器记录emp表的数据变更日志,包括增加、删除、修改
# 创建一张日志表
crater table emp_logs(
    id int(11) not null auto_increment,
    operate varchar(20) not null comment '操作类型, insert/update/delete',
    operate_time datetime not null comment '操作时间',
    operate_id int(11) not null comment '操作表的id',
    operate_params varchar(500) comment '操作参数',
    primary key('id')
)engine=innodb default charset=utf-8;

-- 创建insert触发器
delimiter $
create trigger emp_insert_trigger
after insert
on emp
for each row
begin
	insert into emp_logs(id, operate, operate_time, operate_id, operate_params) 
	values(null, 'insert', now(), new.id,concat('插入后(id:', new.id, 'name:',new.name,'age:',new.age,')'));
end$
delimiter ;
# 测试insert触发器:
insert into emp(id,name,age,salary) values(null,'光明左使',30,3500);

-- 创建update触发器
delimiter $
create trigger emp_update_trigger
after update
on emp
for each row
begin
	insert into emp_logs(id, operate, operate_time, operate_id, operate_params) 
	values(null, 'update', now(), new.id,concat('修改前(id:', old.id, 'name:',old.name,'age:',old.age,
                                                '),修改后(id:', new.id, 'name:',new.name,'age:',new.age,')'));
end$
delimiter ;
# 测试update触发器:
update emp set age = 39 where id = 3;

-- 创建delete触发器
delimiter $
create trigger emp_delete_trigger
after delete
on emp
for each row
begin
	insert into emp_logs(id, operate, operate_time, operate_id, operate_params) 
	values(null, 'delete', now(), old.id,concat('删除前(id:', old.id, 'name:',old.name,'age:',old.age')'));
end$
delimiter ;
# 测试delete触发器:
delete from emp where id = 3;

删除触发器

  • 语法:DROP trigger [schema_name.]trigger_name

    如果没有指定schema_name,默认当前数据库

查看触发器

  • 语法:shwo triggers \G

猜你喜欢

转载自blog.csdn.net/qq_38205875/article/details/109100477
今日推荐