day1
1.1 安装及登录
修改密码:set password = password(‘密码’);
授权远程访问:
grant all privileges on . to ‘root’ @’%’ identified by ‘密码’;
flush privileges; 刷新权限列表
1.2 索引
MySQL官方对索引的定义为:索引 ( index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护者满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据
这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。
一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储在磁盘上。索引是数据库中用来提高性能的最常用的工具
1.2.1 索引优势劣势
优势
① 类似于书籍的目录索引,提高数据检索的效率,降低数据库的IO成本。
② 通过索引列对数据进行排序,降低数据排序的成本,降低CPU消耗。
劣势
① 实际上索引也是一张表,该表中保存了主键与索引字段,并指向实体类的记录,所以索引列也是要占空间的。
② 虽然索引大大提高了查询效率,同时却也降低更新表的速度,如对表进行INSERT、UPDATE、DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息。
1.2.2 索引
索引是在MySQL的存储引擎层中实现的,而不是在服务器层实现的。所以每种存储引擎的索引都不一定完全相同,也不是所有的存储引擎都支持所有的索引类型的。MySQL目前提供了以下4钟索引:
● BTREE索引:最常见的索引类型,大部分索引都支持B树索引。
● HASH索引:只有Memory引擎支持,使用场景简单。
● R-tree索引(空间索引):空间索引是MyISAM引擎的一个特殊索引类型,主要用于地理空间数据类型,通常使用较少,不做特别介绍。
● Full-text(全文索引):全文索引也是MyISAM的一个特殊索引类型,主要用于全文索引,InnoDB从Mysql5.6版本开始支持全文索引。
MyISAM、InnoDB、Memory三种存储引擎对各种索引类型的支持
索引 | InnoDB引擎 | MyISAM引擎 | Memory引擎 |
---|---|---|---|
BTREE索引 | 支持 | 支持 | 支持 |
HASH索引 | 不支持 | 不支持 | 支持 |
R-tree索引 | 不支持 | 支持 | 不支持 |
Full-text | 5.6版本呢之后支持 | 支持 | 不支持 |
我们平常所说的索引,如果没有特别指明,都是指B+树(多路搜索树,并不一定是二叉的)结构组织的索引。其中聚集索引、复合索引、前缀索引、唯一索引默认都是使用B+tree树索引,统称为索引。
BTREE 结构
BTree又叫多路平衡搜索树,一颗m叉的BTree特性如下:
略
BTREE树和二叉树相比,查询数据的效率更高,因为对于相同的数据量来说,BTREE的层级结构比二叉树小,因此搜索速度快。
B+TREE结构
略
由于B+Tree只有叶子节点保存key信息,查询任何key都要从root走到叶子。所以B+Tree的查询效率更加稳定。
MySQL中的B+Tree
MySql索引数据结构对经典的B+Tree进行了优化。在原B+Tree的基础上,增加一个指向相邻叶子节点的链表指针,就形成了带有顺序指针的B+Tree,提高区间访问的性能。
增加指针的目的:增强范围搜索
1.2.3 索引分类
① 单值索引:即一个索引只包含单个列,一个表可以有多个单列索引
② 唯一索引:索引列的值必须唯一,但允许有空值
③ 复合索引:即一个索引包含多个列
1.2.4 索引语法
索引在创建表的时候,可以同时创建,也可以随时增加新的索引。
准备环境:
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 AUTO_INCREMENT=5 DEFAULT CHARSET=utf8
insert into `city`(`city_id`,`city_name`,`country_id`) values (1,'西安',1),(2,'NewYork',2),(3,'北京',1),(4,'上海',1);
CREATE TABLE `country` (
`country_id` int(11) NOT NULL AUTO_INCREMENT,
`country_name` varchar(100) NOT NULL,
PRIMARY KEY (`country_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
insert into `country`(`country_id`,`country_name`) values (1,'China'),(2,'America'),(3,'Japan'),(4,'UK');
创建索引
语法:
CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name [USING index_type] on table_name(index_col_name,...)
实例:为city表中的city_name字段创建索引:
create index idx_city_name on city(city_name);
查看索引
show index from city;
或
show index from city\G;
删除索引
语法:
DROP INDEX index_name ON table_name;
示例:
drop index idx_city_name on city;
ALTER命令
① alter table table_name add primary key(column_list);
该语句添加一个主键,这意味着索引值必须是唯一的,且不能为NULL
② alter table table_name add unique index_name(column_list);
这条语句创建索引的值必须是唯一的(除了NULL外,NULL可能会出现多次)
③ alter table table_name add index_name(column_list);
添加普通索引,索引值可以出现多次。
④ alter table table_name add fulltext index_name(column_list);
该语句指定了索引为FULLTEXT,用于全文索引
1.2.5 索引设计原则
索引的设计可以遵循一一些已有的原则,创建索引的时候请尽量考虑符合这些原则,便于提升索引的使用效率,更高效的使用索引。
① 对查询频次较高,且数据量比较大的表建立索引。
② 索引字段的选择,最佳候选列应当从where子句的条件中提取,如果where子句中的组合比较多,那么应当挑选最常用、过滤效果最好的列的组合。
③ 使用唯一索引,区分度越高,使用索引的效率越高。
④ 索引可以有效的提升查询数据的效率,但索引数量不是多多益善,索引越多,维护索引的代价自然也就水涨船高。对于插入、更新、删除等DML操作比较频繁的表来说,索引过多,会引入相当高的维护代价,降低DML操作的效率,增加相应操作的时间消耗。另外索引过多的话, MySQL也会犯选择困难病,虽然最终仍然会找到一个可用的索引,但无疑提高了选择的代价。
⑤ 使用短索引,索引创建之后也是使用硬盘来存储的,因此提升索引访问的I/O效率,也可以提升总体的访问效率。假如构成索引的字段总长度比较短,那么在给定大小的存储块内可以存储更多的索引值,相应的可以有效的提升MySQL访问索引的I/O效率。
⑥ 利用最左前缀, N个列组合而成的组合索引,那么相当于是创建了N个索引,如果查询时where子句中使用了组成该索引的前几个字段,那么这条查询SQL可以利用组合索引来提升查询效率。
创建复合索引:
CREATE INDEX idx_name_email_status ON table_seller(NAME,emailm,STATUS);
就相当于
对name 创建索引
对name,email 创建了索引;
对name,email,status创建了索引;
1.3 视图
1.3.1 视图概述
视图(View)是一种虚拟存在的表。视图并不在数据库中实际存在,行和列数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的。通俗的讲,视图就是一条SELECT语句执行后返回的结果集。 所以我们在创建视图的时候,主要的工作就落在创建这条SQL查询语句上。
视图相对于普通的表的优势主要包括以下几项。
● 简单:使用视图的用户完全不需要关心后面对应的表的结构、关联条件和筛选条件,对用户来说已经是过滤好的复合条件的结果集。
● 安全:使用视图的用户只能访问他们被允许查询的结果集,对表的权限管理并不能限制到某个行某个列,但是通过视图就可以简单的实现。
● 数据独立:一旦视图的结构确定了,可以屏蔽表结构变化对用户的影响,源表增加列对视图没有影响;源表修改列名,则可以通过修改视图来解决,不会造成对访问者的影响。
1.3.2 创建或者修改视图
创建视图的语法为:
CREATE [OR REPLACE] [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
VIEW view_name [(colum_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]
选项:
WITH [CASCADED | LOCAL] CHECK OPTION 决定了是否允许更新数据使记录不再满足视图的条件。
LOCAL:只要满足本视图的条件就可以更新。
CASCADED(默认值):必须满足所有针对该视图的所有视图条件才能更新。
1.3.3 查看视图
从MySQL5.1 版本开始,使用SHOW TABLES 命令的时候不仅显示表的名字,同时也会显示视图的名字,而不存在单独显示试图的SHOW VIEWS命令。
同样,在使用SHOW TABLE STATUS命令的时候,不但可以显示表的信息,同时也可以显示视图的信息。
1.3.4 删除视图
语法:
DROP VIEW [IF EXISTS] view_name [, view_name] ...[RESTRICT | CASCADE]
示例:
DROP VIEW city_country_view;
1.4 存储过程和函数
1.4.1 存储过程和函数概述
存储过程和函数是事先经过编译并存储在数据库中的一-段SQL语句的集合,调用存储过程和函数可以简化应用开发人员的很多工作,减少数据在数据库和应用服务器之间的传输,对于提高数据处理的效率是有好处的。
存储过程和函数的区别在于函数必须有返回值,而存储过程没有。
函数:是一个有返回值的过程;
过程:是一个没有返回值的函数;
1.4.2 创建存储过程
CREATE PROCEDURE procedure_name ([proc_parameter[,...]])
begin
-- SQL语句
end;
DELIMITER
该关键字用来声明SQL语句的分隔符,告诉MySQL解释器,该段命令是否已经结束了,mysql是否可以执行了。默认情况下,delimiter是分号; 。在命令行客户端中,如果有一行命令以分号结束,那么回车后,mysql将会执行该命令。
1.4.3 调用存储过程
call procedure_name();
1.4.4 查看存储过程
-- 查询db_name数据库中的所有的存储过程
select name from mysql.proc where db='db_name';
-- 查询存储过程的状态信息
show procedure status;
-- 查询某个存储过程的定义
show create procedure test.pro_test1 \G;
1.4.5 删除存储过程
DROP PROCEDURE [IF EXISTS] sp_name;
1.4.6 语法
① 变量
● DECLARE
通过DECLARE可以定义一个局部变量,该变量的作用范围只能在BEGIN…END块中。
DECLARE var_name[,...] type [DEFAULT value]
示例:
CREATE PROCEDURE pro_test1()
begin
declare num int default 10;
select concat('num的值为:',num);
end$
● SET
直接赋值使用SET,可以赋常量或者赋表达式,具体语法如下:
SET var_name = expr [, var_name = expr] ...
示例:
CREATE PROCEDURE `pro_test2`()
begin
declare num int default 0;
set num=num+10;
select num;
end$
也可以通过select…into方式进行赋值操作:
示例:
CREATE PROCEDURE `pro_test3`()
begin
declare num int;
select count(*) into num from city;
select concat('city表中的记录数为:',num);
end
select count(*) into num from city;
这个语句获取了city表中的记录数 通过select into方式赋值给了num
② if条件判断
语法结构:
if serch_condition then statement_list
[elseif search_condition then statement_list]...
[else statement_list]
end if;
需求:
根据定义的身高变量,判定当前身高的所属的身材类型
180及以上 ----------> 身材高挑
170-180 ----------> 标准身材
170以下 ----------> 一般身材
示例:
CREATE PROCEDURE pro_test1()
begin
declare height int default 175;
declare description varchar(50) default '';
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$
③ 传递参数
语法格式:
create procedure procedure_name([in/out/inout] 参数名 参数类型)
...
IN: 该参数可以作为输入,也就是需要调用方传入值,默认
OUT: 该参数作为输出,也就是改啊承诺书可以作为返回值
INOUT:既可以作为输入参数,也可以作为输出参数
● IN-输入
需求:
根据传递的身高变量,判定当前身高的所属的身材类型
示例:
CREATE PROCEDURE pro_test2(IN height INT)
BEGIN
DECLARE description VARCHAR(50) DEFAULT '';
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$
● OUT-输出
需求:
根据传入的身高变量,获取当前身高的所属的身材类型(返回值)
示例:
CREATE PROCEDURE pro_test3(IN height INT,out description varchar(10))
BEGIN
IF height >=180 THEN
SET description = '身材高挑';
ELSEIF height>=170 AND height<180 THEN
SET description = '标准身材';
ELSE
SET description = '一般身材';
END IF;
END$
call pro_test3(188,@description)$
select @description$
小知识
@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;
需求:
给定一个月份,然后计算出所在的季度
CREATE PROCEDURE `pro_test4`(in month int,out description varchar(20))
begin
case
when month>=1 and month<=3 then
set description='第一季度';
when month>=4 and month<=6 then
set description='第二季度';
when month>=7 and month<=9 then
set description='第三季度';
when month>=10 and month<=12 then
set description='第四季度';
end case;
end
⑤ while循环
语法结构:
while search_condition do
sataement_list
end while;
需求:
计算从1加到n的值
create procedure pro_test05(in n int)
begin
declare result int default 0;
declare i int default 0;
while i<=n do
set result = result + i;
set i = i+1;
end while;
select result;
end$
⑥ repeat结构
有条件的循环控制语句,当满足条件的时候退出循环。while是满足条件才执行,repeat是满足条件就退出循环。
语法结构:
REPEAT
statement_lit
UNTIL search_condition
END REPEAT;
需求:
计算从1加到n的值
create procedure pro_test6(in n int)
begin
declare result int default 0;
declare i int default 0;
repeat
set result = result + i;
set i = i+1;
until i>n //注意 until后面没有分号
END REPEAT;
select result;
end$
⑦ loop语句
LOOP实现简单的循环,退出循环的条件需要使用其他的语句定义,通常可以使用LEAVE语句实现,具体语法如下:
[begin_label:] LOOP
statement_list
END LOOP [end_label]
如果不在statement_list中增加退出循环的语句,那么LOOP语句可以用来实现简单的死循环。
⑧ leave语句
用来从标注的流程构造中退出,通常和BEGIN…END或者循环一起使用。下面是一个使用LOOP和LEAVE的简单例子,退出循环:
create procedure pro_test7(in n int)
begin
declare result int default 0;
c:loop
set result = result + n;
set n = n - 1;
if n<=0 then
leave c;
end if;
END loop c;
select result;
end$
⑨ 游标/光标
游标是用来存储查询结果集的数据类型,在存储过程和函数中可以使用光标对结果集进行循环的处理。光标的使用包括光标的声明、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;
示例:
初始化脚本:
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,'Rarity',15,5000),(null,'Twilight',14,4500),(null,'FlutterShy',16,4000),(null,'Pinkie',15,4700);
查询emp表中数据,并逐行获取进行展示
create procedure pro_test8()
begin
declare e_id int(11);
declare e_name varchar(50);
declare e_age int(11);
declare e_salary int(11);
declare emp_result cursor for select * from emp;
open emp_result;
fetch emp_result into e_id,e_name,e_age,e_salary;
select concat('id=',e_id,',name=',e_name,',age=',age,',薪资为:',e_salary);
fetch emp_result into e_id,e_name,e_age,e_salary;
select concat('id=',e_id,',name=',e_name,',age=',age,',薪资为:',e_salary);
fetch emp_result into e_id,e_name,e_age,e_salary;
select concat('id=',e_id,',name=',e_name,',age=',age,',薪资为:',e_salary);
fetch emp_result into e_id,e_name,e_age,e_salary;
select concat('id=',e_id,',name=',e_name,',age=',age,',薪资为:',e_salary);
fetch emp_result into e_id,e_name,e_age,e_salary;
select concat('id=',e_id,',name=',e_name,',age=',age,',薪资为:',e_salary);
close emp_result;
end$
通过多次fetch,可以取得表中数据,但这样的操作显然麻烦且不知道何时结束。
为此,我们使用循环改进
思路1:
获取表中记录数,从而建立循环
select count(*) into num from city;
create procedure pro_test9()
begin
declare i int default 0; //循环用的
declare num int; //表中记录数
declare e_id int(11);
declare e_name varchar(50);
declare e_age int(11);
declare e_salary int(11);
declare emp_result cursor for select * from emp;
select count(*) into num from emp;
open emp_result;
repeat
set i = i+1;
fetch emp_result into e_id,e_name,e_age,e_salary;
select concat('id=',e_id , ', name=',e_name , ',age=',e_age , ', 薪资为:',e_salary);
until i>=num
end repeat;
close emp_result;
end$
思路2:
定义一个边界变量,通过控制边界变量来中止循环
create procedure pro_test10()
begin
declare has_data int default 1;
declare e_id int(11);
declare e_name varchar(50);
declare e_age int(11);
declare e_salary int(11);
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('id=',e_id , ', name=',e_name , ',age=',e_age , ', 薪资为:',e_salary);
until has_data=0
end repeat;
close emp_result;
end$
1.4.7 存储函数
语法结构:
CREATE FUNCTION function_nam([param type ...])
RETURNS type
BEGIN
...
END;
案例:
定义一个存储过程,请求满足条件的总记录数;
create function count_city(countryId int)
returns int
begin
declare cnum int;
select count(*) into cnum from city where country_id = countryId;
return cnum;
end$
select count_city(1)$
删除:
drop function count_city;
1.5 触发器
1.5.1 介绍
触发器是与表有关的数据库对象,指在insert/update/delete之前或之后,触发并执行触发器中定义的SQL语句集合。触发器的这种特性可以协助应用在数据库端确保数据的完整性,日志记录,数据校验等操作。
使用别名 OLD 和 NEW 来引用触发器中发生变化的记录内容,这与其他的数据库是相似的。现在触发器还只支持行级触发,不支持语句级触发。
触发器类型 | NEW和OLD的使用 |
---|---|
INSERT型触发器 | NEW表示将要或者已经新增的数据 |
UPDATE型触发器 | OLD表示修改之前的数据,NEW表示将要或已经修改后的数据 |
DELETE型触发器 | OLD表示将要或者已经删除的数据 |
1.5.2 创建触发器
语法结构:
create trigger trigger_name
before/after insert/update/delete
on tbl_name
[ for each row] -- 行级触发器
begin
trigger_stmt;
end;
示例:
需求: 通过触发器记录emp表的数据变更日志,包含增加,修改,删除;
首先创建一张日志表:
create table emp_logs(
id int(11) not null auto_increment,
operation varchar(20) not null comment '操作类型, inset/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;
create trigger emp_insert
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$
create trigger emp_update
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$
1.5.3 删除触发器
语法结构
drop trigger [schema_name.]trigger_name
如果没有指定 schema_name,默认当前数据库
1.5.4 查看触发器
show triggers;