1.函数
1.1 字符串函数
红线为返回结果。
1.2 数值函数
1.3 日期函数
1.4 流程函数
返回值,就是给那一项重新赋值,比如数学之前是95,这里直接赋值为优秀。
2 约束
对字段约束。
外键的约束,比如两个表通过外键相连,一个表更新了,另一个表上的相关项也得更新。
多个约束之间用空格隔开,用comment表示注释。
2.1 外键约束
红线的地方相当于给外键约束起的别名
当关联了外键,发生删除或者更新时
2.2.1 CASCADE权限
比如用了CASCADE权限
当修改子表中的数据时,父表中也会跟着同步。
比如修改id为6,
然后父表中变成
那如果直接删除子表中的某项呢?用CASCADE。
删除子表中id为3的项
那父表
2.2.2 SETNULL权限
删除子表中id为6的项。
右边都变成null
3 多表查询
3.1 实现多对多关系
提前建好一个学生表和一个课程表,然后创建一个课程表。
student 的id那里也表明为主键。
在中间表创建这两个外键的约束
3.2 实现一对一关系
在任意一方加入外键,关联另外一方的主键,并且把这个外键设为UNIQUE类型。
3.3 实现一对多关系
在多的地方建立外键,指向一的主键。
4 并发事务
有这三种问题。
4.1 脏读
事务B读到另一个事务还没提交的修改。
4.2 不可重复读
事务A在第一步读了一个数据,然后在执行第三步的时候,事务B提交了,里面的事务改变了。
导致A这两次的操作读到的值不同。
4.3 幻读
当事务A在执行完查询语句时,没有查到这个条目时,事务B正好只做了一个插入操作,然后提交。
A在第二步想要插入一个id为1的语句(但这个时候id为1的已经存在),插入不成功。
但我们已经再4.2 解决不可重复读的问题了,所以在第三步再次select,查不到这个数据。
这个数据分明查不到,却不能插入,就是幻读
4.4 事务隔离级别
读未提交
读提交(ORACLE默认隔离级别)
可重复读(MYSQL默认隔离级别)
串行化
这几种隔离级别解决的并发事务
一般会选择数据库的默认隔离级别,不会做修改。
5 存储引擎
输入MYSQL账户密码,在连接层授权认证
5.1 连接层
5.2 服务层
5.3 存储引擎层
不同的存储引擎,索引不一样
我们在建表的时候没有指定引擎,那么将使用默认引擎InnoDB
5.3.1 指定存储引擎
这句话可以查看,当前数据库可以支持哪些引擎
5.3.2 存储引擎简介
innoDB
以innoDB作引擎的表都对应一个 表名.ibd 的表空间文件,存储该表的表结构(frm,sdi)、数据和索引。
最后存储的小单元才是表里的行。它的区和页是大小固定的。
MyISAM
Memory
它的数据都放在内存,所以不用存储索引。
5.3.3 存储引擎的选择
6 索引
无索引的情况下,会顺着表一直往下查。
有索引的情况
索引提高了查询效率,但是表的更新速度和效率变低。
6.1 不同的索引结构
我们通常说的索引都是B+索引。
二叉树的缺点,顺序插入时,会形成一个链表,查询性能大大降低,数据量较大的情况下,层级较深,检索速度慢。
6.1.1 B树
小于20走第一个指针,20-30走第二个指针,......
6.1.2 B+树
所有的数据节点都存在叶子节点。不同于B树
同时叶子节点之间会形成一个单项链表
一个节点会存在一个磁盘块或者说一页
MYSQL在此基础上进行了优化,让叶子节点之间形成了双向链表,这样可以提高区间访问的性能。
6.1.3 hash索引
hash索引的特点
InnoDB能够自动将B+树索引构建成hash索引。
6.2 为什么InnoDB要选择B+树索引结构
三个原因,
1.当用B树时,相较于B+树,它的一页能够存储的键值和指针较少,会导致使得树的高度更高。
2.能够支持范围匹配和排序操作。
6.3 索引分类
当我们给表中的字段作约束的时候,比如UNIQUE,会自动为该字段创建唯一索引。
6.3.1 InnoDB中的索引
那么聚集索引到底长啥样呢?
聚集索引下面挂的是每一行的数据
然后它的第二个字段,肯定是二级索引了,因为有ID,肯定 ID就是聚集索引。
二级索引的下面的每个叶子节点挂的是,id的值,而不是行的数据(减少冗余)
然后我们完成一次查询,查name位Arm的值。
发现A在L之前,走Lee的左侧指针。
然后发现A在G之前,走Greek左侧的指针。
拿到10之后,回表查询,再根据id,来查这一行数据。
可以看到高度为3的时候,存了21939856行数据。
6.4 索引的语法
加了UNIQUE关键字,限定了索引只能有这一个。
不加这两个关键字就是常规索引
如果一个索引只关联一个表的一个字段,称之为单列索引,否则称之为联合索引。
创建索引的启发
在创建联合索引的时候,属性的名字的排序是有讲究的。
6.5 SQL优化
想要对SQL进行优化,就得知道每个sql的执行性能如何。
主要优化查询语句。
6.5.1 SQL的执行频率
红线这里用的是模糊匹配。
可以看到当前数据库是插入为主,还是删除为主,还是更新为主。
6.5.2 慢查询日志
记录了所有查询时间超过,设定的查询时间的sql日志。
slow_query_log=1,开启慢查询的开关
属性值为on说明已经打开了慢查询日志
然后进入这个日志里查看信息。
使用一个命令,tail -f ,只要这个文件有新的信息出来,立马可以看到。
然后我们在去另一个终端查询。
在新出来的信息中,我们逐条分析反馈的消息。
User@Host :哪一个用户在哪一个主机上连接的。
Query_time:总查询耗时
Lock_time:
Rows_sent:返回多少行
use 了哪个数据库。
当前操作的时间
当前查询的具体SQL语句。
6.2.3 查看profile,了解时间都花在哪了
select @@have_profiling ,查看当前数据库是否支持profile。
如果是yes,就是支持。
然后select @@profiling 来查看profile的开关是否打开。如果是1就是打开,如果为0
就set profiling=1,打开。
show profiles就可以查看当时所有的SQL语句的执行情况
那如果我想看16这条SQL语句的执行耗时都耗费在哪了?怎么办呢?
然后就可以看到它们各个阶段的耗费时间。
6.3 explain 执行计划
我们要想评判一条SQL语句的性能,不能只看执行的时间(这只是一个粗略的判断)
那得到的这个结果里的每一项是什么意思呢?
6.3.1 ID相同时
比如多表查询时,
然后用explain ,发现这三个的id都是相同的。则说明表结构的执行是从上到下的,先执行s,再执行sc,然后c表。
6.3.2 id不同时
若id不同则,id值越大,越先执行
若explain,ID不同时,
这个例子就可以看出,嵌套最里面的表c先执行,然后依次从里到外 sc表执行,然后s表执行。
6.3.4 select_type
6.3.5 type
优化的时候尽量往前优化。
1. 查询的时候不访问任何表,才会返回null,
2.唯一性索引查询会,返回const(一般是主键id访问)已经够可以了。
3.当访问一张系统表时,才会返回system
4.当我们使用非唯一性索引的时候,就会出现ref
6.3.6 possible_keys和key和key_len和rows和filtered
possible_keys和key
剩下的。
6.4 查看索引的效率
\G将结果的每个属性转换成一行的表示。
6.4.1 先看没有建立索引的耗时
我们先看查主键id的耗时,为0.00。
因为主键默认建立了主键索引
然后根据id这个字段查,这个字段没有建立索引。
得到的时长为
6.4.2 再看给这个字段建立索引后的查询耗时
构建一个索引花了1分11秒,底层是B+树。
然后再查询就发现。耗时大幅度降低。
6.5 索引使用
6.5.1 最左前缀法则
如果跳过了某一列,则这一列后面的字段的索引将会失效。
比如说user这个表的联合索引,profession在第一列,age在第二列,status在第三列。
然后我们按这个顺序查询,同时也explain分析这个查询。
可以看出status这个索引的字段为5。因为在下面的时候,没有再用它的索引。
如果跳过第一列,就不满足最左前缀法则,后面的索引都不用。
特殊的情况
第一个索引是profession,只要这个查找存在, 那么age和status保持相对位置,也能触发3个索引同时运用。
6.5.2 范围查询(索引出现范围查询(>或<),范围查询右侧的列索引失效
然后我们看看这两种在执行时的执行计划。
索引的总长度为54,当使用>时,很明显没有走最后一个索引。
所以在业务允许的时候,尽量使用>=的范围查询。
6.5.3 索引列运算(不要在索引列上进行运算操作,否则索引失效)
phone这个字段我们提前建立了索引,所以查询速度非常快 。
然后我们试试,在这个字段上进行运算。
用substring来对这个字段操作一下,然后查看一下它们的效率。
我们可以发现phone这个索引已经失效了。
6.5.4 字符串不加引号,索引也会失效
6.5.5 or连接的条件(如果or前的条件中有索引,后面的列中没,则这俩索引都失效)
所以查询时需要or连接的,都要建立索引。
6.6 如果MYSQL发现走索引比走全表还慢
那么它就走全表
6.7 SQL提示
如果这个语句同时满足单列索引和联合索引,那么走哪一个呢?
可以被我们自己指定。
use index指明要使用的索引
ignore表明不用哪个索引
force index表示强制使用那个索引。(因为可能被MYSQL发现走索引比走全表还慢,会帮我们走全表)
6.8 覆盖索引
尽量避免使用select * 的使用。
可以看到select的extra这里。用的时 Using index condition ,性能低。
出现了Using where 和Using in index性能会高。
总结:也就是需要查询的哪些字段,在查询的过程中已经获得了这个字段的值。这个时候不用select *。
比如这句,多了个name字段。,就得回表。
而这一句 ,这里创建的是二级索引,二级索引的叶子节点就是id,所以我们不用再回表查询。
6.9 前缀索引
前n个作为索引
6.9.1 前缀索引的确定
那么如何来确定前缀的长度呢?
比如,先让这句话查 email字段不为空的,有20个,但是可能有重复的。
加了 distinct之后,可以查看不重复的。
所以email这个字段的选择性就可以求出来。不重复的/总的
截取前字符串的前九个,发现选择性就变了。
6.9.2 前缀索引的建立与查询流程
比如这题,前5个字符的区分度已经很好了,然后查到id回表。
6.9.3 联合索引的结构
先按手机号的字段查询,如果相同再按name查询
如果满足覆盖索引,就不用回表。
所以联合索引能够触发覆盖索引的机制,可以尽量多用联合索引
7 索引设计原则
8 SQL优化
8.1 插入数据的优化
如果插入的数据没有那么海量,可以使用insert。
如果插入的是海量的数据,我们使用MYSQL提供的load指令进行插入。
通过load指令直接将磁盘文件加载进去。
但想要使用load指令,得做好以下三步操作。
select @@local_infile;
查看开关是否开启。
然后建立好表结构。
然后根据路径和文件名加载这个数据。
同时指明sql文件中,每个字段由 ','隔开 每行由 '\n' 隔开。
8.2 主键优化
InnoDB最外层是表空间,
表空间存的是一个个的segment段,
段中放的是一个个Extent区,
区里放的是page页,
页当中存放的是一个个的行row。
8.2.1 主键顺序插入页
每页最少放两个数据。
第一页写满了之后再写第二个页。这两个页之间为放一个双向指针。
8.2.2 主键乱序插入页(发生页分裂现象)
插入之前我们已经存放了这么多数据了。
来了个id为50的,应该插在这,但是1号页已经写满。
此时就应该做一个操作,开辟一个新的页,将原来要插的那个页后后面一半数据拿出来,与id为50的数据,放在新申请的页中。
然后再重新设置链表的指针。
8.2.3 页合并现象
如果我们要在innoDB中删除某个数据,比如删除id为16的这行。
它不会真的被删除,只是会被标识删除,然后这里的空间允许其他记录声明使用。
但让一个页中删除的超过了一半,innoDB就会查看,是否合并页来优化空间。
完成合并
8.2.4 主键设计原则
1.尽量降低主键的长度:主键长,二级索引叶子节点中挂的就是主键,二级索引会占用大量的空间,搜索的时候会造成大量的磁盘IO。
2.插入数据时尽量选择顺序插入,选择AUTO_INCREMENT来自增主键。
3.尽量不要使用UUID作为主键,或者其他(比如身份证号)做主键。
4.业务操作时,避免对主键的修改(因为修改主键得修改其对应的索引结构)
8.3 order by 排序操作的优化
Using index的性能要高,Using filesort的性能低。
Using filesort:通过索引或者全表扫描,获得满足条件的数据行,然后在排序缓冲器sort buffer中完成排序操作,那些不是通过索引直接返回排序结果的排序都叫Filesort。简要来说,就是查完在缓冲区里排了序。
Using index:用有序索引查找的结果,结果本来就有序,不用再排。
在展示之前,我们先清理一下索引。
然后我们根据年龄来进行一波排序。
解析一下这个SQL操作,发现后面有Using file sort。因为age字段这个时候没有索引。
总结:sortby的字段,要建立索引
比如我们建立了一个索引针对name和phone字段。
可以发现多了个反向扫描索引,Backward index scan :因为我们在查询时,一个按照升序,一个按照降序。
这两个字段在order by那里也得保持相对顺序。
比如这样,还是会出现file sort
我们在创建索引的时候,每个索引都有自己的默认排序方式,A是ASC
8.3.1 指定索引的排序方式
创建一个索引,它的排序是age的ASC方式,phone的DESC的方式
那如果我们本来就有一个phone字段的索引,它是默认的ASC,这样,就不会走联合索引。
不会出现file sort
索引的方式会改变,
8.3.2 不满足覆盖索引时,也会using filesort
8.3.3 总结
8.4 group by
当profession这个字段没有索引时, 是Using temporary
然后我们创建了包含profession的联合索引,满足了最左前缀法则,再次分析的时候就发现 using index了。
8.5 limit 优化
当起始的位置非常大的时候,查询时间就会变大。
官方给出的方案,通过覆盖索引 加 子查询的方式。
我们先查id,这样可以得到一张表。
想在这个表里通过id的子查询得到每个id的所有数据。发现MSQL不支持这个语法 (in里不能用limit)
所以只能这样写。
给tb_sku起别名 s,和上面子查询得到的表起别名 a。 然后 s.id=a.id来得到s表里的数据。
8.6 count 优化
触发MyISAM引擎的前提是,查询时没有where条件。
count判断字段数量的规则:这个字段的值不是null就 + 1
如果要count null ,那结果就是0,因为null代表计数的字段,字段为null,就是不对字段计数。
8.7 update语句的优化
innoDB的特点,事务,外键,行锁。
begin 开始事务,commit提交事务。
比如我现在要update id为1的这行数据,innoDB会把这行的数据锁住(这是因为name有聚集索引)。
但如果我们这么查询,当name字段没索引时,事务没结束,innoDB给它加的是整张表的锁,如果开启别的客户端,就没办法进行更新操作,整个表都被锁住了。
8.8 总结
9 视图,存储,触发器
9.1 视图
创建一个视图,就是给一条sql查询起别名。
然后这个视图就创建成功了。
视图是一个虚拟存在的表,可以当表一样,操作视图。
9.1.1 查询创建视图的SQL语句
9.1.2 像表一样操作视图
修改视图操作,有两种 create or replace 或者alter
删除视图
9.1.3 视图的检查1
LOCAL:只检查A刚被定义为视图时的条件。
CASCADED:强迫A保持自己的条件和B的条件。级联。
- 如果给V3加上了 wtih loacl option ,则只检查V3这一代的条件。
- 如果给V3加上了,wtih CASCADEED option,则不仅检查V3,还要递归检查V3的祖先。
- 如果啥也没给V3加上,那不检查V3这一代,但是递归检查V3的祖先。
9.1.4 视图的可更新
数据独立的举例:
如果表中有一行的属性变了。
改变这个视图的SQL内容就行。
9.2 存储过程
就是SQL语句的封装和重用。
9.2.1 创建存储过程
9.2.2 查看和删除存储过程
查看itcast数据库下面的存储过程。
可以看到创建这个存储过程的SQL语句。
在命令行创建存储过程时,一见到分号就默认这个存储过程的结束。
设置SQL语句在结束的时候以$$符号结束。
在end这里加上$$就行了。
一旦设置了delimiter ,现在不把 ;作为SQL的结尾。
所以我们得稍作修改。
9.2.3 系统变量
创建三个查询控制台,就有三个会话了。
全局变量:针对所有的会话都有效
9.2.4 用户自定义变量
变量的声明赋值和查询
一种特殊的用select赋值的。
select可以查询也可以赋值。
可以将tb_user的查询结果赋值给用户自定义变量。
9.2.5 存储过程的局部变量
9.2.6 存储过程里的逻辑控制if else
9.2.7 存储过程的参数
不用再查询了,result可以直接返回了。
然后把结果封装进这个用户自定义变量@result
@是用户自定义变量的前缀。
若是传的参数即是输入,又是输出。
9.2.8 存储过程的CASE语法
最后用contact函数来将结果拼成字符串。
9.2.9 循环的语法结构while
while,先检查再做。
9.2.10 循环的语法结构repeat
repeat满足条件退出循环。
先执行一遍,看看是否满足。
9.2.11 loop循环
这两句类似break和continue。
循环名起为sum,leave sum则是结束sum循环。
loop一看就是给嵌套循环设计的。
9.2.12 游标cursor
如果我们想接受一个结果集,显然把结果集放进一个变量里是不可能的。
下图有 select *的结果集,有很多列数据。
把SQL语句的查询结果封装到游标中。
遍历游标获取里面的变量。
会发现有错误,因为必须先声明完变量,再声明游标。
什么时候游标里的内容会被获取完呢?
当执行到最后,游标找不到下一条数据了,就会报错
这个时候我们就需要一个条件处理程序。相当于MYSQL的异常处理
SQLSTATE:MYSQL的状态码。
当满足状态码为 ’0200‘时,执行exit操作,同时关闭游标。
9.3 存储函数
可以在这里限制返回值的类型。
如果没有指明 return type,就会报错。
10 触发器
MYSQL目前只支持行级触发器。
on 后面跟表明,指定触发器绑定哪张表。
10.1 插入数据的触发器
先创建这个表
一旦触发,我们往日志表里插入数据。
用now() 来获得现在的时间,new相当于这一行的对象
10.2 修改数据的触发器
这里不同罢了,修改的需要调用old里面的参数。
10.3 删除数据的触发器
删除得用的行对象是old
11.锁
全局锁,上了只能读,用于备份数据库。只有DQL能用。
11.1 全局锁备份一个数据库
这句话加上全局锁。其他的客户端,只能读不能改。
把这个数据库导成一个SQL文件。
mysqldump是MYSQL提供的工具,必须得在命令行上使用
备份完毕之后释放这个锁。
MYSQL底层innoDB引擎通过快照读来实现。,不用全局锁也能实现一致性。
11.2 表级锁
11.2.1 表锁
解锁的时候,可以直接unlock tables,或者断开客户端连接。
比如客户端1 加了 读锁: 不会阻塞其他客户端的read,仅仅阻塞其他客户端的 write
客户端1 可以read,但是不能写write。
客户端二也可以read,但是不能write 。
比如客户端1 加了 写锁: 阻塞其他客户端的read 和 write
但是本客户端可以读和写
11.2.2 元数据锁
元数据可以理解成,就是表结构。
系统会自动添加元数据锁。
如果某张表存在未提交的事务,我们不能修改这张表的表结构。
有的SQL语句在执行的时候,会加上元数据锁。
EXCLUSIVE就是MDL排他锁。
SHARED_READ和SHARED_WRITE,这俩兼容
SHARED_READ SHARED_WRITE, 和EXCLUSIVE这三个是排斥的。
比如说在客户端1那里,打开了一个事务,用了select语句,自动上了元数据锁SHARED_READ
,然后在客户端2那里,想要alter 表结构操作,就会阻塞,因为alter表结构会加EXCLUSIVE排他锁,
这俩锁是互斥的。
所以当客户端1的事务提交时,客户端2的alter操作才能从阻塞状态转换成执行结束。
11.2.3 意向锁(相当于一个表级的标记变量)
别的客户端要给表加锁的时候,检查意向锁的情况,看看能不能给这个表加锁。
想要加整个表锁,必须得一行一行的检查,看看有没有行锁。效率太低
有了意向锁之后,在给这个表上锁之前,我们只需要检查这个表上有没有意向锁。
11.2.4 意向共享锁IS
首先在客户端1开启事务,用一个select操作,指定锁为read
然后我们来查以下意向锁和行锁的情况。
发现为系统为score表加了 IS锁。
然后我们客户端2给score表加上 read锁。发现可以加成功,因为IS和read兼容。
如果我们在客户端2给score表加上 write锁,发现阻塞,因为IS和write不兼容,
当事务提交成功的时候,行锁和涉及的意向锁都被释放,这个时候客户端2的里的 write锁就能加上。
11.2.5 意向排他锁IX
当客户端1,在score表,进行一个更新操作,这个时候就给表加了IX锁。
这里update by id给当前行加了行锁,系统顺便给这张表上了IX锁。
在客户端2,在score表里加 read或者锁,都会被阻塞。因为检查到了 IX锁。
11.3 行级锁
innoDB是为索引项加锁,而不是真的锁那行数据。
1.行锁
2.间隙锁:不锁该记录,只锁间隙。
间隙,比如6 到12 这两项之间是有间隙,可以插入新数据。
下图为锁住 34 前面的间隙。
3. 临键锁:不仅锁34,而且锁34前面的间隙。
11.3.1 行锁
S: 互斥其他事务的排他锁。
X:互斥其他事务的共享锁、排他锁。
我们平时增删改查加的行锁如下。
我们在实战中演示一下,整一个id查询。
查询锁情况,却没有发现加锁。
唯一索引而不是主键索引。 主键索引是特殊的唯一索引。主键索引的select操作默认不加行锁。
根据name字段来查,如果name字段没索引,就上升为表锁。如果name字段有索引,那就会降到行锁。
11.3.2 间隙锁
1.当我们用主键索引来充当唯一索引时。
然后我们查一下锁的情况
我们想在3-8的间隙里插入数据也不行。
因为索引是要走间隙来判断的。如果找不到 10那个位置,就会上锁10所在的那块间隙。
2. 如果我们要查的name它不是 唯一索引,只是一个普通索引,索引值可能重复。
因为是B+树存索引,其叶子节点是双向链表。
18之前有可能再插入一个name为18的记录,18之后也有可能插入一个name为18的记录。
向右遍历,就会找到18-29这个间隙,找到最后一个不满足的查询(比如找到29)。
锁上前一个 间隙 [ ] 和后一个间隙 [ )
所以它的加锁规则是[12-29),不会锁29。
11.3.3 临键锁
唯一索引的范围查询。
整一波唯一索引的范围查询。
查看它的加锁情况。
加了一个19的行锁,和一个范围为(19,正无穷的]临界锁。
12.innoDB引擎
MySQL5.5版本后默认的引擎。
Trx_id隐藏列,存放最后一个操作的事务的id。
Roll_pointer隐藏列:把修改之前旧的版本写进undo日志中,通过它可以找到该记录修改之前的信息。
两个结构,内存结构和磁盘结构。
12.1 innoDB内存架构
四个部分组成:
自适应哈希索引
缓冲池
change Buffer
日志Buffer
12.1.1 缓冲池
磁盘上经常用的,放在内存里,减少磁盘IO,加快处理速度。
就是跟操作系统那里一样。
12.1.2 change Buffer
如果要增删改的页,不在 buffer pool里,应该先把要变动的数据放在 Change buffer里
由于二级索引的 改变,可能会大幅度的导致 二级索引存放的索引页的数据修改,
比如将 jack修改成rose,那么就有很多索引页(里面存放着索引的信息)的数据修改。
这个时候如果 I/0,就会造成大量的IO(IO需要时间),有了changeBuffer我们可以先在修改缓冲区里索引页,等待缓冲区和磁盘同步一次(只需要一次IO)。
12.1.3 自适应哈希
如果innoDB发现我们访问 某个Buffer Pool里的数据比较频繁,就自动为我们建立哈希索引。
12.1.4 LogBuffer
我们为了提升日志的更新效率,先把日志放在日志缓冲区中,定期刷新到磁盘。
12.2 磁盘结构
12.2.1 系统表空间(就是放系统里的表)
系统表空间:共享表空间,如果没有让表单独有自己的空间,那么这张表就在系统表空间。
12.2.2 单一表空间
file per table 表空间:
12.2.3 通用表空间
通用表空间,就是,自己声明一个空间,用来放表。
12.2.4 undo 表空间
12.2.5 Temporary临时表空间
12.2.6 DoubleWrite Buffer
12.2.7 RedoLog(可以结合看下一章事务
-
mysql脏页:
当内存数据页和磁盘数据页上的内容不一致时,我们称这个内存页为脏页;
内存数据写入磁盘后,内存页上的数据和磁盘页上的数据就一致了,我们称这个内存页为干净页。
就是把内存里的数据页同步到磁盘,通过日志的形式。
12.3 innDB后台线程
这些线程就是把缓冲池里数据,在合适的时候刷新到磁盘中。
AIO是异步IO。
12.4 事务原理
12.4.1 redo log 来保证事务的持久性
如果内存里的数据没有刷新到磁盘中,而且事务已经提交了,也告诉用户事务提交成功,而在脏页刷新的时候失败(没有保证一致性)。
redoLog buffer把日志文件给刷新到磁盘了,变成redo log file,然后过段时间再把脏页的数据刷到磁盘上。
这个日志会循环写,并不会永久保留下来。
12.4.2 undo log来保证事务的原子性。
undo log就是用来回滚,如果你删一条数据,undo log会记得插入这个删除的数据。
如果你从A变动到B,undoLog记录的是数据从 B到A。
undo log存在回滚段里。
12.5 MVCC
12.5.1 当前读
比如说先在客户端1里查一下表的数据,
然后在 客户端2 里完成对表中数据的更新。
这个时候我们再回客户端 1查询,并不能查到表中记录的变更。id为1 那还是java。
因为默认的隔离级别为RR 可重复读。
客户端1也开事务了,如果这个事务没结束,RR 就保证了select的查询结果不会变(实际上已经变了),读取到的是历史版本,不能读取其他事务已经提交的数据。
如果我们现在想在RR条件下,而且事务没提交的条件下,读到当前已经改变的值(当前读)。
我们加一个 lock in share mod,就是实现了当前读
12.5.2 快照读
12.5.1 里面RR情况下,第一次Select会产生快照,第二次select会直接读第一次的快照也就是历史版本。
12.5.3 记录中的隐藏字段
切换到 itcast数据库,我们可以看到以下的表文件。 这些都是独立表空间文件
我们来查看这些表里的表结构:ibd2sdi stu ibd
往下翻,看columns表中有哪些字段。 name属性就是字段名。
12.5.4 MVCC里的undolog日志
快照读,读的也是undoLog里面的旧数据
比如说 修改一条记录
修改id为30的,回滚指针记录历史信息,事务的id也记录下来为2
然后当我们在事务2的基础上更新3, 可以发现跟它的历史版本里记录了事务2。
最终会形成记录之间的链表
12.5.5 read view 读视图(快照读哪个版本)
MVCC里面历史版本的记录有很多,快照读应该读哪个?由readViiew来决定!
12.5.6 RC隔离级别下的快照读
在RC,读已经提交,在查询id为30的时候,正在进行事务5,事务3,4,5还在活动,这个时候建立ReadView,creator_trx_id=5 。
再往下走,又会生成一个Readview
然后我们套用访问规则,看看事务4,3,2 哪个满足条件,用那个版本生成快照。
15.5.7 RR隔离级别下的快照读
readView会复用
快照读会按照reaview的规则来选取历史版本。
13. MYSQL管理
13.1 系统数据库
自带了4个系统数据库,里面放的有系统数据库表
13.1.1 名为mysql的系统数据库
里面的slave表存放主从复制的信息。
user表里有访问数据库用户,和他的权限。
13.1.2 information_schema系统数据库
一些表权限和数据库权限。,还有表空间
在视图里。
13.2 常用工具
13.2.1 命令行mysql工具。
14 MYSQL运维
14.1 日志
14.1.1 错误日志
通过tail命令,查看文件最后50行的内容
如何通过错误的日志,定位到到底是哪出现错误?
tail的-f,可以实时更新。
14.1.2 二进制日志的查看
可是二进制日志文件里记录的是二进制类型的数据,我们要怎么样才能查看呢?
你光用mysql binlog,得转格式
然后就可以看到了
可以修改格式为SQL类型的STATEMENT
只需要修改以下mysql的配置文件。
在配置文件里面 加一句,就改成STATEMENT
然后我们再查,就不需要转格式了,不需要-v,因为statement格式就是sql。
改完配置文件重启,就创建了一个新的二进制文件,而不是覆盖原来的。
拷贝原来的日志文件,然后改成statement格式,新建了一个。
然后我们最新的日志,写入这个最新的statement格式的二进制日志文件。
14.1.3 二进制日志的删除与它的作用
1、恢复,某些数据的恢复需要二进制日志,如当一个数据库全备文件恢复后,我们可以通过二进制的日志进行point-in-time的恢复。
2、复制,通过复制和执行二进制日志使得一台远程的MySQL数据库(一般是slave或者 standby) 与一台MySQL数据库(一般为master或者primary) 进行实时同步。
3、审计,用户可以通过二进制日志中的信息来进行审计,判断是否有对数据库进行注入攻击。
14.1.4 查询日志
查询语句放在查询日志
用sql开启查询日志,每次数据库重启,都得重新开启,所以用配置文件。
可以看到这个查询日志里的内容,删除表的日志也有
14.1.5 慢查询日志
在查询日志下面加两条,开启慢查询模式。
查看一下 慢查询日志是否已经生成。
OK,发现已经生成。
某个SQL语句,没用索引,记录在慢查询日志里。
14.2 MYSQL 的主从复制
将主数据库的DDL和DML操作,通过二进制日志,传到库服务器中。在库上对这些日志重新执行,使得从库和主库的数据保持同步。
MYSQL主从复制有以下三个有点
14.2.1 主从复制的原理
14.2.2 搭建主从复制结构:先多用几个服务器。
先多整几个服务器。生产环境中只开放指定端口。
14.2.3 搭建主从复制结构:主库配置。
这里需要root用户登录进去mysql,然后创建远程连接的账号。
创建一个itcast用户
可以看到二进制日志,用来同步的。
show master status; 查看同步日志。
里面有这几个字段
14.2.4 搭建主从复制结构:从库配置。
但是现在还没和主库之间产生关联。
14.3 分库分表
根据拆策略可以分为垂直和水平。
14.3.1 垂直拆分
就是对结构的拆分。比如这里原来一个库有6张表,现在拆分成三个数据库,每个数据库放两张表。
比如数据库里的某张表访问压力过大,我们可以对这个表进行拆分。
14.3.2 水平拆分
对数据量的拆分。原来一个数据库里的两张表里的数据,分散到三个数据库里。这里是分散数据。
14.3.3 在分库分表下,确定要访问的数据库(shardingJDBC和MyCat)
14.4 Mycat
数据库中间件,我们直接连接mycat即可。
14.4.1 Mycat的安装
就是一个映射数据库的中间件罢了。
14.4.2 MyCat里面的目录
lib里有它依赖的jar包
我们需要替换这个驱动包,上传一个高版本的。传进来是红色的,权限不太对。
在linux下给它授权。
chmod 777 加文件的名字就能给它权限。
14.5 用mycat做一个实例
需求
在这三个数据库上都建一个数据库,db01。
需要找到mycat的配置文件。
用notepad++去连接这个服务器上的文件 ,改完之后就同步。
里面加上我们的服务器信息。
启动mycat
在mysql里连接并登录mycat,-u 是mycat的账户 -p是mycat的访问密码。
然后在mycat里新增数据,就可以看到这些数据被分散到mysql。
怎么分片要看分片规则。默认的就是按id分片。
14.6 mycat配置
server.xml
比如里面有账户的信息。
schma.xml。
rule.xml
里面定义了分片的规则。
14.6.1 schema.xml里面的标签
schema标签
DB01是逻辑库,放逻辑表的。
chekSQLschema的用处
dataNode标签
dataHost标签,类似微服务那做分布式。
14.6.2 rule.xml里面的标签
14.6.3 server.xml里面的标签
定义user账户。
14.7 垂直拆分
table里写的是真实数据库里的表。
1.写好schema.xml
2.写好server.xml,分库的逻辑schema 配好。
将省市区设为全局的表,方便很多业务都用。让每一个分片都存在这三张表。这三张表里的数据一致。
只需要在table标签的type那里改成global,就能把这个表变成全局表。
14.8 水平拆分
auto sharding long是通过id范围来分片,我们这里不用这个规则,我们想让这张日志表的数据均匀分散到三个数据节点上。用mod-long规则来分片,就是取余求模mod
然后给我们的用户那里增加权限,既可以访问shoping也访问 ITCAST这个逻辑库,去server.xml里配置。
14.9 分片规则
14.9.1 范围分片
即通过分片字段的范围,例如拿id字段来分片,id为0-500放在第一个分片。
这个范围我们可以自己定义。
14.9.2 取模mod分片
14.9.3 一致性哈希规则
14.9.4 枚举分片
通过字段的枚举值而分配到节点。
14.9.5 应用指定分片
还有一个默认分片属性,如果没找到就走那里。
14.9.6 固定分片哈希算法
这里&1023 是因为要跟1111111111 10个1 与运算。
14.9.7 字符串哈希解析
没意思,跟前面的都差不多,都是哈希截取。
每一个分片长度都是512
14.9.8 按日期(天)分片
按日期的区间来分片
14.9.9 按月分片
如果到了结束时间,会重新开始计算分片。必须保证分片节点的数量足够,不然会报错
14.10 Mycat的管理与监控
原理
命令行的方式登录并监控
14.10.1 图形化监控界面Mycat-eye![](https://i-blog.csdnimg.cn/blog_migrate/fe31f75e259381593ef15313c1a4edd6.png)
这里不记安装步骤,太低级。
15 读写分离
15.1 用mycat实现一主一从主从复制
15.2 双主双从(防止一主一从有个服务器宕机)原理
互为备胎,master1写了,另外3个都能更新数据。
坏了一个还有一个。
15.3 搭建双主双从
15.3.1 配置master
master1的配置
master2的配置
授权
先登录进master1和master2的mysql服务。两个master都按如下做
创建用户
同步的数据库为db01 db02 db03
15.3.2 配置slave
配好主从复制专用账号
show slave statis \G; 如果看到这两个slave 属性为yes,说明主从复制成功。
15.3.4 关联两个主库
15.3.5 双主双从的读写分离(mycat里配置)