MySQL高级篇——索引、视图、存储过程和函数、触发器的相关概念及操作

news/2024/9/18 4:17:12

文章目录:

1.索引

1.1 索引的优势及劣势

1.2 索引结构

1.2.1 BTREE结构(B树)

1.2.2 B+TREE结构(B+树)

1.2.3 MySQL中的B+Tree

1.3 索引分类

1.4 索引语法

1.5 索引设计原则

2.视图

3.存储过程和函数

3.1 创建存储过程

3.2 调用存储过程

3.3 查看存储过程

3.4 删除存储过程

3.5 存储过程中常用语法

3.5.1 声明变量、变量赋值

3.5.2 if条件判断

3.5.3 传递参数

3.5.4 case结构

3.5.5 while循环

3.5.6 repeat循环

3.5.7 loop + leave循环

3.5.8 游标/光标

3.6 存储函数

4.触发器

4.1 创建触发器

4.1.1 insert型触发器

4.1.2 update型触发器

4.1.3 delete型触发器

4.2 查看触发器

4.3 删除触发器


1.索引

MySQL官方对索引的定义为:索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护者满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据, 这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。如下面的示意图所示 :

左边是数据表,一共有两列七条记录,最左边的是数据记录的物理地址(注意逻辑上相邻的记录在磁盘上也并不是一定物理相邻的)。为了加快Col2的查找,可以维护一个右边所示的二叉查找树,每个节点分别包含索引键值和一个指向对应数据记录物理地址的指针,这样就可以运用二叉查找快速获取到相应数据。

一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储在磁盘上。索引是数据库中用来提高性能的最常用的工具。

1.1 索引的优势及劣势

优势:

  1. 类似于书籍的目录索引,提高数据检索的效率,降低数据库的IO成本。
  2. 通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗。

劣势:

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

1.2 索引结构

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

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

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

1.2.1 BTREE结构(B树)

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

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

以5叉BTree为例,key的数量:公式推导[ceil(m/2)-1] <= n <= m-1。所以 2 <= n <=4 。当n>4时,中间节点分裂到父节点,两边节点分裂。

下面以插入 C N G A H E K Q M F W L T Z D P R X Y S 数据为例,整个B树的演变过程如下:👇👇👇

1). 插入前4个字母 C N G A。n没用超过4,这里正常插入。

2). 插入H,此时数据为 A C G H N,n > 4,所以中间元素G字母向上分裂到新的节点

3). 插入E,K,Q不需要分裂。比G小,存到左子树中;相反存到右子树中。

4). 插入M之后,上面的右子树为 H K M N Q,其中 n > 4了,所以中间元素M字母向上分裂到父节点G

5). 插入F,W,L,T不需要分裂

6). 插入Z之后,上面的右子树为 N Q T W Z,其中 n > 4了,中间元素T向上分裂到父节点中

7). 插入D,上面的左子树为 A C D E F,其中 n > 4了,中间元素D向上分裂到父节点中。然后插入P,R,X,Y不需要分裂

8). 最后插入S,因为 M < S < T,所以走根节点中M的右下方指针,也就是NPQR这个子结点,S进入之后节点 n > 5(N P Q R S),中间节点Q向上分裂,但分裂后父节点DGMT的 n > 5(D G M Q T),所以此时中间节点M会继续向上分裂。则M成为根节点,DG、QT分裂开。

到此,该BTREE树就已经构建完成了, BTREE树 和 二叉树 相比, 查询数据的效率更高, 因为对于相同的数据量来说,BTREE的层级结构比二叉树小,因此搜索速度快。(结合这篇文章开头的截图和上面的B树截图进行对比)

1.2.2 B+TREE结构(B+树)

B+Tree为BTree的变种,B+Tree与BTree的区别为:

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

由于B+Tree只有叶子节点保存key信息,查询任何key都要从root走到叶子。所以B+Tree的查询效率更加稳定。

1.2.3 MySQL中的B+Tree

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

1.3 索引分类

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

1.4 索引语法

首先在这里创建一个数据库,在这个数据库下建两张表,用作测试。

create database demo_01 default charset=utf8mb4;

use demo_01;

CREATE TABLE `city` (
    `city_id` int(11) NOT NULL AUTO_INCREMENT,
    `city_name` varchar(50) NOT NULL,
    `country_id` int(11) NOT NULL,
    PRIMARY KEY (`city_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `country` (
    `country_id` int(11) NOT NULL AUTO_INCREMENT,
    `country_name` varchar(100) NOT NULL,
    PRIMARY KEY (`country_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

然后分别向表中插入几条数据。

insert into `city` (`city_id`, `city_name`, `country_id`) values(1,'西安',1);
insert into `city` (`city_id`, `city_name`, `country_id`) values(2,'NewYork',2);
insert into `city` (`city_id`, `city_name`, `country_id`) values(3,'北京',1);
insert into `city` (`city_id`, `city_name`, `country_id`) values(4,'上海',1);

insert into `country` (`country_id`, `country_name`) values(1,'China');
insert into `country` (`country_id`, `country_name`) values(2,'America');
insert into `country` (`country_id`, `country_name`) values(3,'Japan');
insert into `country` (`country_id`, `country_name`) values(4,'UK');

下面我们来创建索引,语法如下:👇👇👇

CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name
[USING index_type]
ON tbl_name(index_col_name,...)

index_col_name : column_name[(length)][ASC | DESC]

查看索引:show index from table_name;

删除索引:DROP INDEX index_name ON tbl_name;

  • alter table tb_name add primary key(column_list);                        该语句添加一个主键,这意味着索引值必须是唯一的,且不能为NULL
  • alter table tb_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, 用于全文索引

1.5 索引设计原则

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

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

2.视图

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

视图相对于普通的表的优势主要包括以下几项。

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

创建视图,语法如下:👇👇👇

CREATE [OR REPLACE] [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
VIEW view_name [(column_list)]
AS select_statement
[WITH [CASCADED | LOCAL] CHECK OPTION]

修改视图:👇👇👇

ALTER [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
VIEW view_name [(column_list)]
AS select_statement
[WITH [CASCADED | LOCAL] CHECK OPTION]

查看视图:👇👇👇

从 MySQL 5.1 版本开始,使用 SHOW TABLES 命令的时候不仅显示表的名字,同时也会显示视图的名字,而不存在单独显示视图的 SHOW VIEWS 命令。

删除视图:👇👇👇 

DROP VIEW [IF EXISTS] view_name [, view_name] ...[RESTRICT | CASCADE] 


3.存储过程和函数

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

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

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

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

3.1 创建存储过程

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

我们都知道大多数情况下,sql语句都是以 ;分号结尾的。在这里创建存储过程的时候,如果在begin、end的中间加上sql语句最后的分号,那么就会报错。

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

3.2 调用存储过程

call procedure_name();

下面创建完存储过程,可以来调用存储过程。

这里也可以在Navicat中看到上面创建好的存储过程。

3.3 查看存储过程

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

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

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

3.4 删除存储过程

DROP PROCEDURE [IF EXISTS] sp_name;

3.5 存储过程中常用语法

3.5.1 声明变量、变量赋值

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

直接赋值使用 SET,可以赋常量或者赋表达式,具体语法如下:

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

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

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

3.5.2 if条件判断

if search_condition then statement_list

[elseif search_condition then statement_list] ...

[else statement_list]

end if;

3.5.3 传递参数

create procedure procedure_name([in/out/inout] 参数名  参数类型)
...
IN :  该参数可以作为输入,也就是需要调用方传入值 , 默认
OUT:  该参数作为输出,也就是该参数可以作为返回值
INOUT: 既可以作为输入参数,也可以作为输出参数

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

@@global.sort_buffer_size : 这种在变量前加上 "@@" 符号, 叫做 系统变量 

3.5.4 case结构

CASE

    WHEN search_condition THEN statement_list

    [WHEN search_condition THEN statement_list] ...

    [ELSE statement_list]

END CASE;

3.5.5 while循环

while search_condition do
    statement_list
end while;

3.5.6 repeat循环

有条件的循环控制语句, 当满足条件的时候退出循环 。while 是满足条件才执行,repeat 是满足条件就退出循环。

REPEAT

    statement_list

    UNTIL search_condition

END REPEAT;

3.5.7 loop + leave循环

LOOP 实现简单的循环,退出循环的条件需要使用其他的语句定义,通常可以使用 LEAVE 语句实现,具体语法如下:

[begin_label:] LOOP
    statement_list
END LOOP [end_label]

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

3.5.8 游标/光标

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

声明光标:

DECLARE cursor_name CURSOR FOR select_statement; 

OPEN光标:

OPEN cursor_name; 

FETCH光标:

FETCH cursor_name INTO var_name [, var_name] ... 

CLOSE光标:

CLOSE cursor_name; 

下面,为了演示光标的案例,先创建一张emp表。

create table emp(
    id int(11) not null auto_increment ,
    name varchar(50) not null comment '姓名',
    age int(11) comment '年龄',
    salary int(11) comment '薪水',
    primary key(`id`)
)engine=innodb default charset=utf8;

insert into emp(id,name,age,salary) 
values(null,'金毛狮王',55,3800),(null,'白眉鹰王',60,4000),(null,'青翼蝠王',38,2800),(null,'紫衫龙王',42,1800);

下面第一种方法是 逐行获取光标,从中取出数据。

上面逐行获取的方法虽然可行,但是如果数据过多,则显得代码量较大、冗余度较高。

所以下面采用repeat循环的方法来获取光标。(截图中的Display请忽略,应该是粘贴的时候格式有点问题)

3.6 存储函数

CREATE FUNCTION function_name([param type ... ])
RETURNS type
BEGIN
...
END;


4.触发器

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

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

4.1 创建触发器

create trigger trigger_name
before/after insert/update/delete
on tbl_name
[ for each row ]  -- 行级触发器
begin
    trigger_stmt ;
end;

为了测试,这里首先创建一张emp_logs表,用来记录触发器相关的操作日志信息。

create table emp_logs(
    id int(11) not null auto_increment,
    operation 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=utf8;

4.1.1 insert型触发器

创建完insert型触发器之后,执行两条insert语句,即可在 emp_logs 表中看到信息。

create trigger emp_logs_insert_trigger
after insert 
on emp
for each row
begin
	insert into emp_logs(id,operation,operate_time,operate_id,operate_params)
	values(null,'insert',now(),new.id,concat('插入后(id:',new.id,', name:',new.name,',
age:',new.age,', salary:',new.salary,')'));
end$

insert into emp(id,name,age,salary) values(null, '光明左使',30,3500);
insert into emp(id,name,age,salary) values(null, '光明右使',33,3200);

4.1.2 update型触发器

创建完update型触发器之后,执行update语句,即可在 emp_logs 表中看到信息。

create trigger emp_logs_update_trigger
after update
on emp
for each row
begin
	insert into emp_logs(id,operation,operate_time,operate_id,operate_params)
	values(null,'update',now(),new.id,concat('修改前(id:',old.id,', name:',old.name,',
age:',old.age,', salary:',old.salary,') , 修改后(id',new.id, 'name:',new.name,',
age:',new.age,', salary:',new.salary,')')); 
end$

update emp set age = 39 where id = 3;

4.1.3 delete型触发器

创建完delete型触发器之后,执行delete语句,即可在 emp_logs 表中看到信息。

create trigger emp_logs_delete_trigger
after delete
on emp
for each row
begin
	insert into emp_logs(id,operation,operate_time,operate_id,operate_params)
	values(null,'delete',now(),old.id,concat('删除前(id:',old.id,', name:',old.name,',
age:',old.age,', salary:',old.salary,')'));
end$

delete from emp where id = 5;

4.2 查看触发器

show triggers;

4.3 删除触发器

drop trigger [schema_name.]trigger_name;

http://www.niftyadmin.cn/n/711254.html

相关文章

安装完操作系统后,必备开发软件安装

WinRAROfficeESETChromeFireFoxJavaSkypeTeamViewerGitHubXshell、XftpPowerDesignerStarUMLNotepadMyEclipseZendStudioVisualStudioReSharperAnkhSVNMySQLOracleSqlServerPlSql迅雷万能五笔UltraISOColorPicAdobeReaderIntelliJ IDEA

day16--HTML、CSS、JavaScript总结

HTML 一大堆的标签&#xff1a;块级、行内 CSS position background text-align padding font-size background-image z-index opacity float(clear:both) line-height border color display 补充&#xff1a;页面布局 JavaScript 6.for循环 for (var item in [11,22,33,44…

常用RGB色值表

RGB值 RGB值 RGB值黑色000#000000黄色2552550#FFFF00浅灰蓝色176224230#B0E0E6象牙黑413633#292421香蕉色22720787#E3CF57品蓝65105225#4169E1灰色192192192#C0C0C0镉黄25515318#FF9912石板蓝10690205#6A5ACD冷灰128138135#808A87dougello23514285#EB8E55天蓝135206235#87CEEB石…

JavaSE面试题——自增运算(局部变量表 + 操作数栈)

1.Go&#xff01;&#xff01;&#xff01; 如下代码的运行结果&#xff1a;&#x1f447;&#x1f447;&#x1f447; public class Test {public static void main(String[] args) {int i 1;i i;int j i;int k i i * i;System.out.println("i" i);System.out…

网络爬虫基本原理(一)

本文转载至 http://www.cnblogs.com/wawlian/archive/2012/06/18/2553061.html 网络爬虫是捜索引擎抓取系统的重要组成部分。爬虫的主要目的是将互联网上的网页下载到本地形成一个或联网内容的镜像备份。这篇博客主要对爬虫以及抓取系统进行一个简单的概述。 一、网络爬虫的基…

基于fullcalendar制作的日程管理小demo

一、项目地址&#xff1a; https://github.com/linqian123... 二、项目功能概述&#xff1a; 该项目是基于fullcalendar而制作的日程管理&#xff0c;fullcalendar是一个基于jquery的日历插件&#xff0c;在该项目中&#xff0c;我们可以在日历上编辑我们的日程&#xff0c;并将…

群辉助手Synology Assistant使用教程

下载 百度网盘链接直接下载即可 链接&#xff1a;https://pan.baidu.com/s/1XlQEcTCqBTsOgp-761jdOg?pwd5vyf 提取码&#xff1a;5vyf --来自百度网盘超级会员V5的分享 安装 直接双击安装&#xff0c;等待安装完成 能搜索到上图应用说明安装成功 使用 点击搜索按钮&…

让Win8自动登录免输入密码的小技巧

按WinR键&#xff0c;输出“netplwiz”&#xff0c;单击“确定”&#xff0c;弹出“用户帐户”窗口。将第一个画框上的勾选去掉——应用——弹出自动登录输入你的密码——确定——确定完成。重启看看电脑是不是不用输入密码也可以自动登录了&#xff0c;注销后还要输入密码的。…