黑马Mysql重点笔记(2万字)
在存储引擎层实现的,不同的存储引擎有不同的结构。sql提示,是优化数据库的一个重要手段,简单来说,就是sql语句中加入一些人为的提示来达到优化操作的目的explain select * from tb_user use index(idx_user_pro) where profession = '软件工程'explain select * from tb_user ignore index(id
注意,该笔记来自于黑马Mysql的听课记录且尚未扩展,希望通过这篇博客你能完美入门mysql。
Mysql DataBase Management System(DBMS)
SQL分类:
DCL DDL DQL DML
数据类型
数值类型
字符串数据
日期类型
DDL data definition language
1.查询所有数据库 show databases
2.查询当前数据库 select database
3.创建 create database[if not exists] 数据库名 [default charset 字符集] [collate]排序规则
4.删除 drop database[if exists]数据库名
5.use 数据库名 使用指定的数据库
6.DESC 表名 查询表结构
7.show create table表名 查询指定表的建表语句
8.添加字段 alter table 表名 ADD 字段名 类型(长度) [comment 注释] [约束]
9.修改数据类型 alter table 表名 modify 字段名 新数据类型(长度)
10.修改字段名和字段类型 alter table 表名 change 旧字段名 新字段名 类型(长度)[comment注释] [约束]
11 修改表名 alter table 表名 rename to 新表名
12 删除表 drop table[if exists] 表名
13 删除指定表,并重新创建该表 truncate table 表名(在删除表时,表中的全部数据也会被删除)
DML data manipulation language
1.insert into 表名(字段名1, 字段名2...) values(值1,值2); 给指定字段添加数据
2.insert into 表名 values(值1, 值2);给全部字段添加数据
3.insert into 表名(字段名1, 字段名2) values(值1, 值2...), (值1, 值2...), (值1, 值2, ...); 批量添加数据
4.insert into 表名(值1, 值2...), (值1, 值2...), (值1, 值2...); 批量添加数据
注意
插入数据时,指定的字段顺序需要与值的顺序是一 一对应的
字符串和日期型数据应该包含在引号中
插入的数据大小,应该在批量添加数据
5.update 表名 set 字段名=值1 字段名=值二,...[where 条件] 修改数据
6.delete from 表名 [where 条件] 删除语句
注意
7.7delete 语句的条件可以有,也可以没有,如果没有条件,则会删除整张表的所有数据
8.delete语句不能删除某一个字段的值(可以使用update)
DQL data query language
略,已拿捏(把力扣数据库的题刷完就行了, 2-3天就能刷完)。
DCL data control language
1.use mysql;
2.select * from user 查询用户
3.create user '用户名'@'主机名' identified by ’密码'; 创建用户
4.alter suer '用户名'@'主机名' identified with mysql_native_password by '新密码'; 修改用户密码
5.drop user '用户名'@'主机名' 删除用户
权限控制
6.show grants for '用户名'@'主机名';查询权限
7.grant 权限列表 on 数据库.表名 to '用户名'@'主机名' 授予权限
8 revoke 权限列表 on 数据库名.表名 from '用户名'@'主机名' 撤销权限
多个权限之间,使用逗号分隔
授权时,数据库名和表名可以使用*进行通配,代表所有。
函数
是指一段可以直接被另一段程序调用的程序或代码
字符串函数
数值函数
日期函数
流程函数
约束
概念:约束时作用于表中字段上的规则,用于限制存储在表中的数据
目的:保证数据库中数据的正确,有效性和完整性
分类:
注意:约束是作用于表中字段上的,可以在创建表/修改表的时候添加约束
外键约束
删除外键
alter table 表名 drop foreign key 外键名称
多表查询
分类:
一对多
多对多
一对一
笛卡尔积:笛卡尔乘积是指在数学中,两个集合A集合和B集合的所有组合情况.(在多表查询时,需要消除无效的笛卡尔积)
连接查询
内连接:
相当于查询A,B交集部分数据
隐私内连接:select 字段列表 from 表1,表2 where 条件...;
显示内连接:select 字段列表 from 表1 [inner] join 表2 on 连接条件...;
外连接
左外连接:查询左表所有数据,以及两张表交集部分数据
select 字段列表 from 表1 left [outer] join 表二 on 条件...;
右外连接:查询右表所有数据,以及两张表交集部分数据
select 字段列表 from 表1 right [outer] join 表二 on 条件...;
自连接
当前表与自身的连接查询,自连接必须使用表名
select 字段列表 from 表A 别名A join 表A 别名B on 条件...;
子查询
标量子查询(子查询结果为单个值)
列子查询(子查询结果为一列) in, not in, any, some, all,
行字查询(子查询结果为1行)= != <> in not in
表子查询(子查询结构为多行多列) in
根据子查询位置,分为: where之后,from之后,select之后
事务
是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败(默认mysql的事务是自动提交的,也就是说,当执行一条DML语句,mysql会立即隐私的提交事务)
查看/设置事务提交方式
select @@autocommit;
set @@autocommit=0
开始事务
start transaction/begin
提交事务
commit
回滚事务
rollback
事务的四大特性
并发事务问题
隔离
mysql体系结构
连接层
最上层是一些客户端和链接服务,主要完成一些类似于连接处理,授权认证即相关的安全方案。服务器也会为安全接入的每个客户端验证它所具有的操作权限
服务层
第二层架构主要完成大多数的核心服务功能,如sql接口,并完成缓存的查询,sql的分析和优化,部分内置函数的执行。所有跨存储引擎的功能也在这一层实现,如过程,函数等。
引擎层
存储引擎真正的负责了mysql中数据的存储和提取,服务器通过api和存储引擎进行通信。不同的存储引擎具有不同的功能,这样我们可以根据自己的需要,来选取合适的存储引擎。
存储层
主要是将数据存储在文件系统上,并完成与存储引擎的交互
存储引擎 InnoDB
存储引擎memory和MyIsam
三者差异对比
存储引擎选择
InnoDB: 是mysql的默认存储引擎,支持事务,外键。如果应用对事务的完整性有比较高的要求,在并发条件要求下数据的一致性,数据操作除了插入和查询之外,还包含很多的更新,删除操作。那么InnoDB存储引擎是比较合适的选择.
MyISAM:如果应用是以读操作和插入操作为主,只有很少的更新和删除操作,并且对事务的完整性,并发性要求不是很高,那么选则这个存储引擎是非常合适的。
MeMory(不推荐,以被替代): 将所有数据保存在内存中,访问速度快,通常用于临时表即缓存。memory的缺陷就是对表的大小有限制,太大的表无法缓存在内存中,而且无法保障数据的安全性。
索引
概念:是帮助Mysql高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。
索引概述
索引结构
在存储引擎层实现的,不同的存储引擎有不同的结构。
B+树索引
优点
相对于二叉树,层级更少,搜索效率高。
相对于Hash索引,B+tree支持范围匹配即排序操作
对于B-tree,无论是叶子结点还是非叶子结点,都会保存数据,这样导致一页中存储的键值减少,指针跟着减少,要同样保存大量数据,只能增加树的高度,导致性能降低
Hash索引
索引分类
InnoDB中的两种索引
回表查询:
先通过二级索引拿到名字对应的id,之后通过聚集索引拿到对应id的对应行的数据
语法
1.create [unique | fulltext] index index_name on table_name(index_col_name) 创建索引
2.show index from table_name; 查看索引
3.drop index index_name on table_name 删除索引
sql性能分析
mysql客户端连接成功后,通过show [session|global] status命令可以提供服务器状态信息。通过如下指令,可以查看当前数据库的Insert, update, delete, select的访问频次
show golbal status like 'Com___(3次)'
慢查询日志
慢查询日志记录了所有执行时间超过指定参数(long_query_time, 单位:秒,默认:10秒) 的所有sql语句的日志
mysql的慢查询日志默认没有开启,需要在Mysql的配置文件(/etc/my.cnf)中配置如下信息: show_query_log = 1 开启mysql慢日志查询开关
long_query_time = 2 设置慢日志的时间为2秒,sql语句执行时间超过2秒,就会视为慢查询,记录慢查询日志
查看慢日志文件中记录的信息/var/lib/mysql/localhost-slow.log
show varialbes liek 'slow_query_log' 查询慢日志是否开启
profile详情
show profiles能够在做sql优化时帮助我们了解时间都耗费到哪里去了。通过have_profiling参数,能够看到当前mysql是否支持profile操作 select @@have_profiling;
默认profiling时关闭的,可以通过set语句在session/global级别开启profiling;set profiling = 1;
show profiles 查看每一条sql的耗时基本情况
show profile for query query_id 查看指定query_id的sql语句各个阶段的耗时情况
show profile cpu for query query_id; 查看指定query_id的sql语句cpu的使用情况
explain
explain 或者desc命令获取mysql如何执行select语句的信息,包括在select语句执行过程中表如何连接和连接的顺序。
explain/desc select 字段列表 from 表名 where 条件
索引使用
最左前缀法则
如果索引了多列(联合索引), 要遵守最左前缀法则。最左前缀法则指的是查询从索引的最左列开始,并且不跳过索引中的列。如果跳跃某一列,索引将部分失效(后面的字段索引失效)
范围查询
联合索引中,出现范围查询(>, <) 范围查询右侧的列索引失效
索引列运算
1.不要在索引列上进行运算操作,索引将失效
2.字符串不加单引号,索引将失效
3.如果仅仅是尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引失效。
4.用or分割开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到。
5.如果mysql评估使用索引比全表更慢,则不使用索引
6.尽量使用覆盖索引(查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到),减少select
7.当字段类型为字符串(varchar, text)时,有时候需要索引很长的字符串,这会让索引变得很大,查询时,浪费大量的磁盘IO,影响查询效率。此时可以只将字符串的一部分前缀,建立索引,这样可以大大节约索引空间,从而提高索引效率。 : create index idx_xxxx on table_name(column(n));
单列索引:即一个索引只包含单个列
联合索引:即一个索引包含了多个列
在业务场景中,如果存在多个查询条件,考虑针对于查询字段建立索引时,建议建立联合索引,而非单列索引。
索引设计原则
1.针对数据量较大,且查询比较频繁的表建立索引
2.针对于常作为查询你条件(where), 排序(order by), 分组(group by) 操作的字段建立索引
3.尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高
4.如果时字符串类型的字段,字段的长度较长,可以针对字段的特点,建立前缀索引
5.尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率。
6.要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也决越大,会影响增删改的效率
7.如果索引列不能存储null值,请在创建表时使用not null约束它。当优化器知道每列是否包含null值时,它可以更好地确定哪个索引最有效地用于查询
索引总结
sql提示
sql提示,是优化数据库的一个重要手段,简单来说,就是sql语句中加入一些人为的提示来达到优化操作的目的
use index: explain select * from tb_user use index(idx_user_pro) where profession = '软件工程'
ignore index: explain select * from tb_user ignore index(idx_user_pre) where profession = '软件工程'
force index: explain select * from tb_user force index(idx_user_pre) where prefession = '软件工程';
SQL优化
insert优化
批量插入
Insert into tb_test values(1, 'Tom'), (2, 'Cat'), (3, 'Jerry');
手动提交事务
start transaction
insert into tb_test values(1, 'Tom'), (2, 'Cat'), (3, 'Jerry');
inser into tb_test values(4, 'Tom'), (5, 'Cat'), (6, 'Jerry');
insert into tb_test values(7, 'Tom'), (8, 'Cat'), (9, 'Jerry');
commit
主键顺序插入
主键乱序插入:8 1 9 21 88 2 4 15 89 5 7 3
主键顺序插入:1 2 3 4 5 7 8 9 15 21 88 89(性能高于乱序插入)
主键优化
主键设计原则
1.满足业务需求的情况下,尽量降低主键的长度
2.插入数据时,尽量选择顺序插入,选择使用auto_increment自增主键
3.尽量不要使用uuid做主键或者是其他自然主键,如省份证号
4.业务操作时,避免对主键的修改
order by优化
1.using filesort: 通过表的索引或全表扫描,读取满足条件的数据行,然后在排序缓冲区sort buffer中完成排序操作,所有不是通过索引直接返回排序结果的排序都叫FileSort排序
2.using index: 通过有序索引顺序扫描直接返回有序数据,这种情况即为using index,不需要额外排序,操作效率高
explain select id, age, phone form tb_user order by age, phone 没有创建索引时,根据age, phone进行排序
create index idx_user_age_phone_aa on tb_user(age, phone) 创建索引
explain select id, age, phone from tb_user order by age, phton 创建索引后,根据age, phone进行升序排序
explain select id, age, phone from tb_user order by age desc, phone desc 创建索引后,根据age,phone进行降序排序
explain select id, age, phone from tb_user order by age asc, phone desc; 根据age,phone进行一个升序,一个降序
create index idx_user_age_phone_ad on tb_user(age asc, phone desc) 创建索引
explain select id, age, phone from tb_user order by age asc, phone, desc; 根据 age,phone进行一个升序,一个降序
group by优化
1.分组操作时,可以通过索引来提高效率
2.分组操作时,索引的使用也是满足最左前缀法则的
drop index id_user_pro_age_sta on tb_user 删除掉目前的联合索引 idex_user_pro_age_sta
explain select profession, count(*) from tb_user group by profession 执行分组操作,根据profession字段分组
create index idx_user_pro_age_sta on tb_user(profession, age, status) 创建索引
explain select profession, count(*) from tb_user group by profession 执行分组操作,根据profession字段分组
explain select profession, count(*) from tb_user group by profession, age; 执行分组操作,根据profession字段分组
limit优化
一个常见又非常头痛的问题就是limit 2000000,10 此时需要mysql排序前2000010记录,仅仅返回2000000-2000010的记录,其他记录丢弃,查询排序的代价非常大
优化思路 一般分页查询时,通过创建,覆盖索引 能够比较好地提高性能,可以通过覆盖索引加子查询形式进行优化
explain select * from tb_sku t, (select id from tb_sku order by id limit 2000000,10) a where t.id = a.id
count优化
explain select count(*) from tb_uer
MyISAM 引擎把一个表地总行数存在了磁盘上,因此执行count(*)地时候会返回这个数,效率很高
InnoDB 引擎就麻烦了,它执行count(*) 的时候,需要把数据一行一行地从引擎里面读出来,然后累计
优化:自己计数
update优化
update student set no = '2000100100' where id = 1
update student set no = '2000100105' where name = '韦一笑'
InnoDB的行锁是针对索引加的锁,不是针对记录家加的锁,并且该索引不能失效,否则会从行锁升级为表锁
总结
视图
创建:create[or replace] view 视图名称[(列名 列表)] as select 语句[with[cascaded | local] check option ]
查询:
查看创建视图语句:show create view 视图名称
查看视图数据:select * from 视图名称 修改
1.create [or replace] view 视图名称[(列名列表)] as select 语句 [with [cascaded | local] check option]
2.alter view 视图名称[(列名列表)] as select 语句 [with [cascaded | local] check option]
删除
drop view [if exists] 视图名称 [视图名称]...
视图检查选项
当使用WITHCHECKOPTION子句创建视图时,MySQL会通过视图检查正在更改的每个行,例如插入,更新,删除,以使其符合视图的定义。MySQL允许基于另一个视图创建视图,它还会检查依赖视图中的规则以保持一致性。为了确定检查的范围,mysql提供了两个选项:CASCADED和LOCAL,默认值为CASCADED。
cascaded:如果当前视图有检查选项,则插入数据要满足包括当前视图条件以及满足当前视图所依赖的视图的条件。如果当前视图没有检查选项,则插入数据要满足当时视图所依赖视图有检查选项及其依赖的视图的条件。
local: 是递归的查找当前视图所依赖的视图是否有检查选项,如果有,则检查;如果没有,就不做检查
视图的更新
简单: 视图不仅可以简化用户对数据的理解,也可以简化他们的操作。那些被经常使用的查询可以被定义为视图,从而使得用户不必为以后的操作每次指定全部的条件
安全:数据库可以授权,但不能授权到数据库特定行和特定的列上。通过视图用户只能查询和修改他们所能见到的数据
存储过程
特点
封装,复用
可以接收参数,也可以返回数据
减少网络交互,效率提示
查看:
select * from information_schema.routines where routine_schema = 'xxx' --查询指定数据库的存储过程及状态信息
show create procedure 存储过程名称 -- 查询某个存储过程的定义
删除:
drop procedue [if exists] 储存过程名称
在命令行中,执行创建存储过程的sql时,需要通过关键字delimiter指定sql语句的结束符
存储结构
系统变量
用户定义变量
局部变量
if
语法:
if 条件1 then
elseif 条件2 then
........ 可选
else
........ 可选
end if;
用法示例
create procedure p3() begin declare score int default 58; declare result varchar(10); if score >= 85 then set result := '优秀'; elseif score >= 60 then set result := '及格'; else set result := '不及格'; end if; select result; end; call p3();
参数
用法示例1
create procedure p4(int score int, out result varchar(10)) begin declare score int default 58; declare result varchar(10); if score >= 85 then set result := '优秀'; elseif score >= 60 then set result := '及格'; else set result := '不及格'; end if; end; call p4(18, @result); select @result;
用法示例2
create procedure p5(inout score double) begin set score := score * 0.5; end; set @score = 78; call p5(@score); select @score;
case
while
while循环是有条件的循环控制语句。满足条件后,再执行循环体中的SQL语句。具体语法为:
# 先判定条件,如果条件为true,则执行逻辑, 否则,不执行逻辑 while 条件 do sql逻辑 end while;
repeat(类似于do{}while)
是有条件的循环控制语句,当满足条件的时候退出循环。
# 先执行一次逻辑,然后判定逻辑是否满足,如果满足,则退出。如果不满住,则继续下一次循环 repeat sql逻辑 until 条件 end depeat;
loop
实现简单的循环,如果不在sql逻辑中增加退出循环的条件,可以用其来实现简单的死循环。loop可以配合一下两个语句使用
-
leave: 配合循环使用,退出循环
-
iterate: 必须用在循环中,作用是跳过当前循环剩下的语句,直接进入下一次循环
[begin_label:] loop sql逻辑 end loop [end_label];
用法示例
create procedure p1o(in n int) begin declare total int default 0; sum:Loop if n<=0 then Leave sum; end if; if n%2 = 1 then set n := n - 1; iterate sum; end if; set total := total + n; set n := n - 1 end loop sum; select total; end; call p10(10);
cursor游标
是用来存储查询结果集的数据类型,在存储过程和函数中可以使用游标对结果集进行循环的处理。游标的使用包括游标的声明,open, fetch, close 其语法分别如下
声明游标
-
declare 游标名称 cursor for 查询语句
打开游标
-
open 游标名称
获取游标记录
-
fetch 游标名称 into 变量[,变量 ];
关闭游标
-
close 游标名称
handler条件处理程序
可以用来定义在流程控制结构执行过程中遇到问题时相应的处理步骤(详情参考官方文档)。具体语法为:
declare handler_action handler for condition_value [, condition_value]... statement; handler_action continue: 继续执行当前程序 exit: 中止执行当前程序 condition_value sqlstate sqlstate_value: 状态码, 如02000 sqlwarning: 所有以01开头的sqlstate代码的简写 not found: 所有以02开头的sqlstate代码的简写 sqlexception: 所有没有被sqlwarning 或 not gound捕获的sqlstate代码的简写
存储函数
触发器
触发器是与表有关的数据库对象,指在inser/update/delete之前或之后,触发并执行触发器中定义的sql语句集合。出发器这种特性可以协助应用在数据库端确保数据的完整性,日志记录,数据校验等操作
使用别名OLD和NEW来引用触发器中发生变化的记录内容,这与其他的数据库是相似的。现在触发器还只支持行级触发,不支持语句级触发
创建
create trigger trigger_name before/after insert/update/deleteon tbl_name for each row --行级触发器 begin trigger_stmt; end;
查看
show triggers
删除
drop trigger [schema_name.]trgger_nam; ##如果没有指定schema_name,默认为当前数据库
小总结
锁
锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中,除传统的计算资源(cput, ram, i/o)的争用外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性,有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂。
全局锁
: 锁定数据库中的所有表
全局锁就是对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的DML的写语句,DDL语句,已经更新操作的事务提交语句都被阻塞。
其典型的使用场景是做全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性
数据库中加全局锁,是一个比较重的操作,存在以下问题
-
如果在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆。
-
如果从库上备份,那么在备份期间从库不能执行主库同步过来的二进制日志(binlog),会导致主从延迟
在InnoDB引擎中,我们可以在备份时加上参数 --single-transaction 参数来完成不加锁的一致性数据备份
mysqldump --single-transaction -uroot -p[password] itcast> itcast.sql
表级锁
: 每次操作锁住整张表。锁定粒度大,发生锁冲突的概率最高,并发度最低。应用在MyISAM, InnoDB, BDB等存储引擎中。
表锁
-
表共享读锁 (read lock)
-
表独占写锁 (write lock)
语法:
-
加锁: lock tables 表名... read/write。
-
释放锁 unlock tables / 客户端断开连接。
元数据锁(meta data lock, MDL)
MDL加锁过程是系统自动控制,无需显示使用,在访问一张表的时候会自动加上。MDL锁主要作用是维护表元数据的数据一致性,在表上有活动事务的时候,不可以对元数据进行写入操作。为了避免DML与DDL冲突,保证读写的正确性
在MySql5.5中引入了MDL, 当对一张表进行增删改查的时候,加MDL读锁(共享);当对表结构进行变更操作的时候,加MDL写锁(排他)
意向锁
-
意向共享锁(IS): 由语句select ...lock in share mode添加, 与表锁共享锁(read)兼容,与表锁排它锁(write)互斥
-
意向排他锁(IX): 由insert, update, delete, select...for update 与表锁共享锁(read)及排它锁(write)都互斥。意向锁之间不会互斥
select object_schema, object_name, index_name, lock_type,lock_mode, lock_data from performance_schema.data_locks
行级锁
: 每次操作锁住对应的行数据。每次操作锁住对应的行数据。锁定粒度最小,发生锁冲突的概率最低,并发度最高。应用在InnoDB存储引擎中。
InnoDB的数据是基于索引组织的,行锁是通过对索引项加锁来实现的,而不是对记录加的锁。对于行级锁,主要分为以下三类。
行锁(record Lock):
锁定单个行记录的锁,防止其他事务对此进行update和delete。在RC, RR隔离级别下都支持
-
共享锁 (S): 允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
-
排他锁 (X): 允许获取排他锁的事务更新数据,阻止其他事务获得相同数据集的共享锁和排他锁
默认情况下,InnoDB在 repeatable read事务隔离级别运行,InnoDB使用 next-key 锁进行搜索和索引扫描,以防止幻读。
-
针对唯一索引进行检索时,对已存在的记录进行等值匹配时,将会自动优化为行锁
-
InnoDB的行锁是针对于索引加的锁,不通过索引条件检索数据,那么InnoDB将对表中的所有记录加锁,此时就会升级为表锁
间隙锁
锁定索引记录间隙(不含改记录),确保索引记录间隙不变, 防止其他事务在这个间隙进行insert,产生幻读。在RR隔离级别下都支持。
-
索引的等值查询(唯一索引),给不存在的记录加锁时,优化为间隙锁
-
索引上的等值查询(普通索引),向右遍历时最后一个值不满足查询需求时,next-key lock退化为间隙锁。
-
索引上的范围查询(唯一索引)-- 会访问到不满足条件的第一个值为止
间隙锁唯一目的是防止其他事务插入间隙。间隙锁可以共存,一个事务采用的间隙锁不会阻止另一个事务在同一间隙上采用间隙锁
临键锁
行锁和间隙锁组合,同时锁住数据,并锁住数据前面的间隙Gap。在RR隔离级别下支持。
小总结
InnoDB引擎
逻辑结构
架构
MySql5.5版本开始,默认使用InnoDB存储引擎,它擅长事务处理,具有崩溃恢复特性,在日程开发中使用非常广泛。下面是InnoDB架构图,左侧为内存架构,右侧为磁盘架构。
内存架构
BufferRead
changeBuffer
Adaptive Hash Index
log Buffer
服务器%80(待确定--高性能Mysql)会分配给缓存区,以便提高速率
磁盘架构
后台线程(将缓存区中的数据刷新到磁盘文件中)
事务(ACID)
是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。
特性
-
原子性(Atomicity): 事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
-
一致性(Consistency): 事务完成时,必须使所有的数据都保持一致状态
-
隔离性(Isolation): 数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
-
持久性(Durability): 事务一旦提交或回滚,它对数据库中的数据的改变是永久的的。
原理
-
redo log
重做日志,记录的是事务提交时数据页的物理修改,是用来实现事务的持久性。
该日志文件由两部分组成:重做日志缓冲(redo log buffer) 以及重做日志文件(redo log file),前者是在内存中,后者在磁盘中。当事务提交后会把所有修改信息都存到该日志文件中,用于在刷新脏页到磁盘,发生错误时,进行数据恢复使用。
MVCC(Multi-version-concurrency-Control[多版本并发控制])
指维护一个数据的多个版本,使得读写操作没有冲突,快照读为Mysql实现MVCC提供了一个非阻塞读功能。MVCC的具体实现,还需要依赖于数据库记录中的三个隐式字段,undo log日志,readView。
当前读
读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。对于我们日常的操作,如:select... lock in share mode(共享锁), select...for update , update, insert, delete(排他锁)都是一种当前锁
快照读
简单的select(不加锁) 就是快照读,快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞锁。
-
Read Committed: 每次select, 都生成一个快照读
-
Repeatable Read:开启事务后第一个select语句才是快照读的地方
-
Serialilzable: 快照读会退化为当前读。
MVCC实现原理
记录隐藏字段
undo log日志
-
回滚日志,在insert, update, delete的时候产生的便于数据回滚的日志.
-
当insert的时候,产生的undo log日志只在回滚时需要,在事务提交后,可被立即删除.
-
而update, delete的时候,产生的undo log日志不仅在回滚时需要,在快照读时也需要,不会立即被删除.
ReadView
快照读sql执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的id).
ReadView中包含了四个核心字段
不同的隔离级别,生成ReadView的时机不同
RC
read committed: 在事务中每一次执行快照读时生成ReadView
RR
repeatable read: 仅在事务中第一次执行快照读时生成ReadView, 后续复用该ReadView
RC
RR
总结
InnoDB总结
Mysql管理
系统数据库(四个)
常用工具
该Mysql不是指mysql服务,而是指mysql的客户端工具
语法:
• mysql [options] [database]
选项:
• -u, --user = name # 指定用户名
• -p, --password[=name] # 指定密码
• -h, --host=name # 指定服务器IP或域名
• -P, --port=pot # 指定连接端口
• -e, --execute=name #执行sql语句并退出
-e 选项可以在mysql客户端执行sql语句,而不用连接到mysql数据库再执行,对于一些批处理脚本,这种方式尤其方便
• mysql -uroot -p123456 -e "select * from stu";
mysqladmin
mysqladmin是一个执行管理操作的客户端程序。可以用它来检查服务器配置的当前状态,创建并删除数据库等。
mysqladmin --help #eg: mysqladmin -uroot -p123456 drop 'test01'; mysqladmin -uroot -p123456 version;
mysqlbinlog
由于服务器生成的二进制日志文件以二进制格式保存,所以如果想要检查这些文本的文本样式,就会使用到mysqlbinlog日志管理工具。
语法: mysqlbinlog [options] log-files log-files2... 选项: -d, --database=name #指定数库名称,只列出指定的数据库相关操作 -o, --offset=# #忽略掉日志中的前n行命令 -r,--result-file=name #将输出的文本格式日志输出到指定文件 -s, --short-form #显示简单格式,省略掉一些信息 --start-datatime=date1 --stop-datetime=date2 #指定日期间隔内的所有日志 --start-position=pos1 --stop-position=pos2 #指定位置间隔内的所有日志
mysqlshow
客户端对象查找工具,用来很快地查找存在哪些数据库,数据库中的表,表中的列或者索引。 语法: • mysqlshow [options] [db_name [table_name [col_name]]] 选项: • --count 显示数据库及表的统计信息(数据库,表均可以不指定) • -i 示例 • mysqlshow -uroot -p2143 --count #查询每个数据库的表的数量及表中记录的数量 • mysqlshow -uroot -p2143 test --count #查询test库中每个表中的字段书,及行数 • mysqlshow -uroot -p2143 test book --count #查询test库中book表的详细情况
mysqldump
mysqldump客户端工具用来备份数据库或在不同数据库之间进行数据迁移。备份内容包含创建表,及插入表的sql语句。
mysqlimport/source
mysqllimport是客户端数据导入工具,用来mysqldump 加-T参数后导出的文本文件
mysql工具总结
总结
日志
日志
错误日志
错误日志是mysql中最重要的日志之一,它记录了当mysql启动和停止时,以及服务器在运行过程中发现任何严重错误时相关信息。当数据库出现任何故障导致无法正常使用时,建议首先查看此日志。
该日志是默认开启的,默认存放目录/var/log/ , 默认文件名为mysqld.log.查看日志位置
-
show variables like '%log_error%'
二进制日志(binlog 主从复制)
记录了所有的DDL(数据定义语言)语句和DML(数据操纵语言)语句,但不包括数据查询(select, show)
语句:
作用:1. 灾难时的数据恢复。2. mysql的主从复制。在Mysql8版本中,默认二进制日志是开启着的,涉及到的参数如下。
show variables like '%log_bin%'
日志删除
对于比较繁忙的业务系统,每天生成的binlog数据巨大,如果长时间不清除,将会占用大量磁盘空间。可以通过以下几种方式清理日志。
也可以在Mysql的配置文件中配置二进制日志的过期时间,设置了之后,二进制日志过期会自动删除。
show variables like '%binlog_expire_logs_seconds%';
查询日志
查询日志中记录了客户端的所有操作语句,而二进制日志不包含查询数据的sql语句。默认情况下,查询日志是未开启的。如果需要开启查询日志,可以设置一下配置。
慢查询日志
记录了所有执行时间超过参数long_query_time设置值并且扫描记录数不少于min_examined_row_limit的所有的SQL语句的日志,默认未开启。long_query_time默认为10秒,最小为0.精度可以到微妙。
#慢查询日志 slow_query_log = 1 #执行时间参数 long_query_time = 2
默认情况下, 不会记录管理语句,也不会记录不使用索引进行查找的查询。可以使用log_slow_admin_statements和更改此行为log_queries_not_using_indexes,如下所述。
# 记录执行较慢的管理语句 log_show_admin_statements = 1 # 记录执行较慢的未使用索引的语句 log_queries_not_using_indexes = 1
主从复制
概述
将主数据库的DDL和DML操作通过二进制日志传到从库服务器中,然后在从库上对这些日志重新执行(也叫重做),从而使得从库与主库的数据保持同步。
MysQL支持一台主库同时向多台从库进行复制,从库同时也可以作为其他从服务器的主库,实现链状复制。
原理(如何进行主从复制)
搭建
主库配置
-
修改配置文件 /etc/my.cnf
# mysql服务ID,保证整个集群环境中唯一,取值范围: 1-2^32-1 默认为1 server-id = 1 #是否只读, 1代表只读, 0代表读写 read-only=0 #忽略的数据,指不需要同步的数据库 binlog-ignore-db=mysql #指定同步的数据库 binlog-do-db=db01
-
启动mysql
-
登录mysql, 创建远程连接的账号,并授予主从复制权限
#创建itcast用户,并设置密码,该用户可在任意主机连接该mysql服务 create user 'itcast'@'%'identified with mysql_native_password by 'root@password' #为'itcast'@'%'用户分配主从复制权限 grant replication slave on *.* to 'itcast'@'%';
-
通过指令, 查看二进制坐标
show master status
从库配置
-
修改配置文件 /etc/my.cnf
#mysql服务ID,保证整个集群环境中唯一,取值范围: 1-2^32-1, 和主库不一样即可 server-id = 2 #是否只读, 1代表只读,0代表读写 read-only = 1 --> 普通用户 #禁用超级管理员读取 super-read-only = 1
-
重启mysql服务
-
从库配置
-
开启同步操作
start replica; #8.022之后 start slave; #8.0.22之前
测试
总结
分库分表
问题分析
拆分策略
垂直拆分
垂直分库:以表为依据,根据业务将不同表拆分到不同库中
特点
-
每个库的表结构都不一样
-
每个库的数据也不一样
-
所有库的并集是全量数据
垂直分表: 以字段为依据,根据字段属性将不同字段拆分到不同表中。
特点
-
每个表的结构都不一样
-
每个表的数据也不一样,一般通过一列(主键/外键) 关联
-
所有表的并集是全量数据
水平拆分
水平分库: 以字段为依据,按照一定策略,将一个库的数据拆分到多个库中。
特点
-
每个库的表结构都一样
-
每个库的数据都不一样
-
所有库的并集是全量数据
水平分表: 以字段为依据,按照一定策略,将一个表的数据拆分到多个表中
特点
-
每个表的表结构都是一样
-
每个表的数据都不一样
-
所有表的并集是全量数据
实现技术
Mycat概述
Mycat是开源的,活跃的,基于Java语言编写的Mysql数据库中间件了。可以像使用mysql一样来使用mycat, 对于开发人员来说根本感觉不到Mycat的存在。
优势
-
性能可靠稳定
-
强大的技术团队
-
体系完善
-
社区活跃
Mycat入门
目录结构
-
bin: 存放可执行文件,用于启动停止mycat
-
conf: 存放Mycat的配置文件
-
lib:存放Mycat的项目依赖包(jar)
-
logs: 存放mycat的日志文件
Mycat配置
分片配置
schema.xml
: 涵盖了MyCat的逻辑库,逻辑表,分片规则,分片节点及数据源的配置
-
schema标签 配置逻辑库逻辑表
-
schema标签(table) 数据节点
-
datanode标签 节点主机和关联的数据源
-
datahost标签
(server.xml)
ruel-xml
定义所有拆分表的规则,在使用过程中可以灵活的使用分片算法,或者对同一个分片算法使用不用的参数,它让分片过程可配置化。主要包含两类标签:tableRule, Function
-
system标签
-
user标签
启动服务
切换到Mycat的安装目录,执行如下指令,启动Mycat:
#启动
bin/mycat start
#停止
bin/myCat stop
Mycat启动之后,占用端口号8066
Mycat分片
分片测试
通过如下指令,就可以连续并登录MyCat
mysql -h 192.168.200.210 -p 8066 -uroot -p123456
垂直分库
配置
水平分表
分片规则
范围分片
: 根据指定的字段及其配置的范围与数据节点的对应情况,来决定该数据属于哪一个分片
取模分片
根据指定的字段值与节点数量进行求模运算,根据运算结果,来决定该数据属于哪一个分片
一致性hash
枚举分片
通过在配置文件中配置可能的枚举值,指定数据分布到不同数据节点上,本规则适用于按照省份,性别,状态拆分数据等业务
应用指定算法
运行阶段由应用自主决定路由到哪个分片,直接根据字符子串(必须是数字)计算分片号
固定hash算法
类似于十进制的求模运算,但是为二进制的操作,例如,取id的二进制低10位与1111111111(1023)进行位&运算。
字符串hash解析
截取字符串中指定位置的字符串,进行Hash算法,算出分片。
按天分片
按自然月分片(法如其名)
Mycat管理及监控
Mycat原理
Mycat管理
默认开通2个端口,可以在server.xml中进行修改。
-
8066数据访问端口,即进行DDL操作和DML
-
9066数据库管理端口,即mycat服务管理控制功能,用于管理mycat的整个集群状态
mysql -h 192.168.200.210 -p 9066 -uroot -p123456
Mycat-eye
Nycat-Web(Mycat-eye)是对mycat-server提供监控服务,功能不局限于对mycat-server使用。他通过JDBC连接对Mycat,Mysql监控,监控远程服务器(目前仅限于linux系统)的cpu, 内存,网络,磁盘。
Mycat-eye运行过程中需要依赖zookeeper,因此需要先安装zookeeper.
总结
读写分离
简单地说是把对数据库的读和写操作分开,以对应不同的数据库服务器。主数据库提供写操作,从数据库提供读操作,这样能有效地减轻单台数据库地压力。
通过MyCat即可轻易实现上述功能,不仅可以支持MySql,也可以支持Oracle和SQL Server。
一主一从
MySQl的主从复制,是基于二进制日志(binlog)实现的
一主一从读写分离
MyCat控制后台数据库的读写分离和负载均衡由schema.xml文件datahost标签的balance属性控制
双主双从
一个主机Master1用于处理所有写请求,它的从机Slave1和另一台主机Master2还有它的从机Slave2负责所有读请求。当Master1主机宕机后,Master2主机负责写请求,Master1, Master2互为备机。架构图如下
主库配置 (Master1-192.168.200.211)
修改配置文件 /etc/my.cnf
#创建itcast用户,并设置密码,该用户可在任意主机连接该mysql服务
create user 'itcast'@'%' identified with mysql_native_password by 'root@password'
#为 'itcast'@'%'用户分配主从复制权限
grant deplication slave on *.* to 'itcast'@'%'
#通过指令, 查看两台主库的二进制日志坐标
show master status
从库配置
双主双从读写分离
配置
测试
登录MyCat,测试查询及更新操作,判定是否能够进行读写分离,以及读写分离的策略是否正确。
当主库挂掉一个之后,是否能够自动切换。
总结
总结
感谢观看!!!
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)