MYSQL进阶,高端的理解,MVCC,日志,慢查询,最左匹配原则,一般查询日志和慢查询日志的输出形式启动时日志控制mysqldumpslow-总结慢查询日志文件Mysqlbinlog处理二

目录

一般查询日志和慢查询日志的输出形式

启动时日志控制

mysqldumpslow-总结慢查询日志文件

Mysqlbinlog处理二进制文件

mysqlbinlog binlog.00001

慢查询sql优化思路

SQL执行时间长的原因

 等待时间长(大概率是锁表,或锁冲突导致的),让查询一直处于等待的状态

执行的时间长:

合理设计并且利用索引

explain

Extra列

MYSQL优化

联合索引的最左匹配原则

联合索引的设计策略1.高频的查询条件 将最频繁出现在where,join,order by中的列放到左侧

2.列区分度:

3.排序与分组需求

4.覆盖索引优化

设计覆盖索引案列(最左匹配)

MVCC

索引失效场景

Orderby和groupby 会用到联合索引吗

like如何避免全表查询

Mysql如何实现可重入锁

mysql的存储引擎

数据库三大日志


日志类型,日志信息

错误日志:mysqlId在启动,运行或者停止时候遇到的问题(启动失败,运行崩溃)

一般查询日志(General query log):已建立的客户端连接和从客户端收到的语句

慢查询日志(slow query log):执行时间超过long_query_time指定秒数的查询(优化的场景)

二进制日志(Binary log):更改数据的语句(用于主从复制)

中继日志(Relay log):从源服务器接收到的数据更改(来源于集群中的主服务,比如我们抄学霸的作业,我们可以拍照,然后再抄,节省时间)

DDL日志:DDL语句执行的操作

回滚日志(undo log):用于事务的回滚操作

重做日志:用于服务器崩溃恢复

默认情况下,除windows上的错误日志外,不启用任何日志,Linux下默认开错误日志和二进制日志

在服务器运行期间可以控制一般查询和慢查询日志的禁用和开启,也可以更改日志名

一般查询日志和慢查询日志记录可以写入日志表,日志文件或者两者同时写入

默认情况下,所有启用的日志将写入数据目录,可以通过刷新日志强制服务器关闭并重新打开日志文件

通过FLUSH LOGS语句刷新日志来强制服务器关闭,并且重新打开日志文件,也可以使用mysqladmin的flush-logs或者refresh参数,或者mysqldump的--flush-logs或者--master-data

中继日志仅用于主从复制过程中的从服务器。

一般查询日志和慢查询日志的输出形式

如果启用一般查询日志和慢查询日志,日志的输出方式可以指定为日志文件或者mysql系统中的general_log和slow_log表,也可以两者同时锁定

启动时日志控制

log_output系统变量指定日志输出的形式,但是并不会真正启用日志,log_output可以有三个值,分别是:table(表),FILE(文件),NONE(不输出),可以同时指定多个值,并且用逗号隔开,未指定值时默认是FILE,如果列表中存在NONE则其他的不生效,也就是说NONE的优先级更高

可以通过general_log系统变量的值来控制一般查询日志的开启1与禁用0,如果日志指定自定义的路径和文件名可以使用general_log_file系统变量(绝对路径)

通过设置slow_query_log系统变量的值来控制慢查询日志的开启1和禁用0,如果要为日志自定义的路径或者文件名就可以使用slow_query_log_file系统变量

mysqldumpslow-总结慢查询日志文件

当某些查询语句执行时间过长,执行时间超过设定的阈值时,我们称这个查询为慢查询

慢查询相关信息用日志记录下来称为慢查询日志,mysqldumpslow可以解析慢查询日志并且汇总其内容:mysqladmin status -uroot -plcl15604007179

当前服务器内容少,暂时没有慢查询,

比如select *from student where id=1

   select *from student where id=10      此时这个id会被记录称

select*from student where id=N

通常情况下,mysqldumpslow会将查询分组并显示摘要输出,一般会把数字和字符串用N和S代替。

count执行的次数

Time单次的耗时

Lock申请与释放锁所用的时间

Rows获取数据所用的时间

mysqldumpslow

Mysqlbinlog处理二进制文件

对数据库的增删改,都会被描述成一个事件,每个事件以二进制文件录在一个文件里面

称为Binary Log

mysqlbinlog 能够以文本格式,显示二进制日志文件的内容

mysqlbinlog binlog.00001

at xxx     一个事件在日志文件中其实偏移位置

end_log_pos 事件在日志中结束的偏移位置

慢查询sql优化思路

SQL执行时间长的原因

 等待时间长(大概率是锁表,或锁冲突导致的),让查询一直处于等待的状态

执行的时间长:

  • 查询sql写的烂
  • 索引失效
  • 关联join太多
  • 服务器调优及各个参数设置

慢查询优化思路:

  • 优先选择优化,高并发执行的SQL,因为高并发执行的SQL带来的后果,更加严重

比如下面两种情况:

  • SQL1:每小时执行1w次,每次20个IO,优化之后每次18个IO,每小时节省2万次IO
  • SQL2:每小时10次,每次2w个IO,优化之后,每次减少2k个IO,每小时省2w次IO

SQL1vsSQL2

  • 高并发通常指单位时间内执行次数多(如 QPS 高),而不是单次资源消耗高。
  • SQL1 的执行频率(每小时 10,000 次)远高于 SQL2(每小时 10 次),因此:
    • SQL1 是高并发查询
    • SQL2 是低频但高资源消耗的查询

定位优化对象的性能瓶颈

  • IO:数据访问的时候,消耗太多的时间,查看是否使用了正确的索引
  • CPU:数据运算花费了太多的时间,数据运算的分组,排序是否存在问题。
  • 网络带宽:如果网络带宽受限,数据传输的速度也将受到限制,从而导致查询的响应时间增加了

明确优化的目标:明确数据库当前的状态,数据库与当前该条SQL的关系

                               当前SQL的具体的功能:尽量选择优化那些对业务影响比较大的SQL。

从explain执行计划入手

  只有explain能告诉你当前SQL的状态

永远使用小表(小的结果集)驱动大表(大的结果集) 比如

for(int i=0;i<5;i++){

for(int j=0;j<1000;j++){

 如果小的循环在外层,对于数据库连接,只需要连接5次,进行5k次操作,否则我就连接1000次每次5次操作。

尽可能在索引中完成排序:

      因为索引本身是排好序的,排序字段在索引中的话,速度是比较快的

只获取自己需要的列

      不用select *

只去使用最有效的过滤条件:

       误区:where后面的条件越多越好,实际上是用最短的路径访问到数据才是最好的,即选择最有效的,比如用id就可以确定

尽量避免复杂的join和子查询

      每条sql的join操作,建议不超过3张表

     将复杂sql拆分成多个小sql,单个表执行,获取到结果区程序中封装就好

合理设计并且利用索引

      1.较为频繁的作为查询条件的字段,应该创建索引

      2.唯一性太差的字段不适合单独的去创建索引。比如性别  状态    状态字段,当一条query所返回的数据超过了全表的15%的时候,不需要使用索引扫描了

      3.更新频繁的字段,不适合创建索引,因为索引字段被更新,还要维护索引文件

       4.不会出现在where条件中的字段,不需要创建索引

如何选择合适的索引?

   1.对于单键索引,尽量选择针对当前查询效果更好的索引

   2.选择联合索引时候,当前查询中过滤性最好的字段,应该放到索引的最左侧

explain

    type列:

如果对主键或者UNIQUE唯一索引的等值查询,type的类型就为const,最多只返回1行数据,速度非常快,const基础上表里只有一条数据(system,但是不在innodb引擎里面,一般在MySAM引擎是可以出现的),接下来看一下eq_ref,ref,ref_or_null,

eq_ref通常发生在联表查询中关联的条件某一张表的主键或者UNIQUE唯一非空索引

性能,仅次于const

ref最常见,当满足索引的最左原则,同时并不走主键或者UNIQUE唯一非空索引,则为REF

对于非聚簇索引的单值查询,一般都为ref,

ref_or_null和ref大差不差,在上面的基础上,增加null值的查询,则为ref_or_null。

由于查询null值需要扫描整个索引树的行信息,所以比ref慢。

index_merge:将多个搜索结果合并成一个,还可以对结果排序,从而降低查询代价

  永远去用小的结果集驱动大的结果集,目的就是减少内层表读取的次数

range:between,like,in,大于,小于,都是range,由于要对索引树扫描,效率并不高

index和all:两种都是全表扫描,区别index只需要查询索引树就可以拿到结果,all还需要遍历所有行,两种效率都低

Extra列

using index就是覆盖索引,也就是想要查找的数据都在索引树中,不需要回表再去查询聚簇索引,这样就可以减少不必要的查询,从而提升查询效率

using index condition 索引下推,index Condition Pushdown,即ICP,(5.6后的优化手段)假如搜索时候,需要大量回表,在回表之前,会先把处理过滤逻辑,下推到存储引擎汇总进行。过滤整理后,发到Server层进行处理,这样就减少了发给Server层的数据量和次数,提升了效率

using where和using index相对,所有的过滤动作都由Server层处理,效率会比较低,从分析可以看出,假如但看效率低话,using index>using index condition>using where(记得去优化)

using MRR:对二级索引查询时候,会优先对二级索引的查询结果缓存并进行排序,然后统一去聚簇索引中回表查询,这样可以把随机IO优化成顺序IO,提升效率,需要关闭mrr_cost_based才能确保使用mrr.

using join buffer(BNL,BKA)

A,B两表关联查询,A的关联列上有索引,而B的没有,就会发生BNL优化,从A表去失调数据,放到Join Buffer中,再去全表扫描B表和Join 和Buffer这10行进行关联,循环这一步,直到A表的所有数据都关联完为止。虽说这是优化,减少B表的扫描次数,但是还是慢,规避

BKA ,在BNL的基础上,B表如果有索引,配合MRR,将JoinBuffer中的行进行排序之后去B表对应索引中查询,而无序全表扫描  默认关闭

using union,如果多个查询条件都是索引,那么会对索引进行合并,会出现using union,一般伴随着typeindex_merge.

using temporary:使用到了临时表,比如group by,distinct ,union等语句时候,可能用到临时表

using filesort:在查询之后,进行一些排序,在查询之后,需要单独进行一次排序,会出现using filesort,当然我们可以进行一些优化,不需要这次额外排序,只需要将条件和排序两个字段组成联合索引即可。这样定位到条件之后,由于联合索引,排序字段本身有序,不需要额外排序了。

联合索引的最左匹配原则

最左匹配原则是对联合索引的一个查询优化,既定的一个规则

联合索引式由两个及以上的字段组成的索引,就叫做联合索引,生效条件是必须从最左侧(A)开始且开始连续使用索引列

本质原因:索引的B+树按联合索引顺序排序(先按A排序,A相同再按照B排序)

依据第一个,第二个字段,按顺序的匹配,才能用联合索引

比如联合索引(A,B,C)

where A=1       使用最左列A,触发索引

where A=1 AND B=2 连续使用A和B

where A=1 and B=2 and C=3   全列匹配,效率最高

where A=1 and C=3 仅A生效,C无法使用索引(中间缺少B)

where B=2 and C=3 不生效,未从最左列A开始,全表扫描

where A>1 and B=2 部分生效   ,仅A生效,范围查询后无法使用B(B需要再内存中过滤)

(name,city,age)

varchar(50)如何计算  -4*50加2个变长(null)

联合索引的设计策略
1.高频的查询条件 将最频繁出现在where,join,order by中的列放到左侧

高频查询  : where     name='张三' and age=15

最优索引(name,age)

2.列区分度:

区分度高的列(唯一值多)放到左侧,快速过滤更多数据

区分度=count(Distinct colum/count(*) (值越大,区分度越高) sex :男女,性别区分度,2/100就是

name有200个值,gender有两个值,优先吧name放到左侧(name:gender)

3.排序与分组需求

假如查询Order by或者Group by 将排序列假如索引,并且保持一致

where name='张三' order by age desc 

最优索引:(name,age)

4.覆盖索引优化

若查询字段均包含在索引中,可以避免回表(Extra列显示using index)

select name,city,name from user where name='张三';

覆盖索引:(name,city,age) 

设计覆盖索引案列(最左匹配)

 查询1:where name='张三' and city ='北京' order by age desc

查询2:where country='中国' and name='张三'

索引设计:

方案1:(name,city,age)  优化查询1,覆盖索引

方案2:(name,country)优化查询2   

根据查询频率决定优先级更高的索引。

误区

低区分度的放到最左         过滤效率低                                  按区分度从高到低排列

忽略排序/分组字段           导致filesort临时表(性能下降)    将排序列加入索引保持顺序一致

过度追求覆盖索引              索引字段过多,写入性能下降            包含高频查询字段

思考一下

索引(name,city,age)是否可以优化where city='北京' and name='张三‘

可以,优化器会优化把顺序自动调整为name='张三' and city='北京

MVCC

多版本数据,每个修改操作生成数据行的信版本,旧版本通过Undo Log保留

隐藏字段:每行数据包含两个隐藏字段:

DB_TRX_ID :最后一次修改该行事务的id,6字节

DB_ROLL_PTR:指向旧版本数据的指针(Undo Log地址)

ReadView读视图

   m_ids:生成ReadView时活跃且未提交的事务ID列表(除当前事务之外的其他事务ID列表)

   min_trx_id:活跃事务中的最小ID

   max_trx_id:生成ReadView时下一个待分配的事务ID     生成ReadView的最大的ID+1即可

   creator_trx_id:当前事务的ID

MVCC是啥,解决什么问题,什么

每个事务修改一次,就要去生成一个新的版本,不同的事物去读不同的版本

在不可重复读的隔离级别下,让事物每次读到同一个版本的数据,这样每次读到的都一样了,就能避免可重复读的问题。

所以把修改的数据版本记录到一个undo log日志中,给表增加一个隐藏字段回滚指针,回滚指针指向这个undo log日志         (一个事务来查找数据,我怎么知道哪个版本的数据)

说明生成版本事务的数据还没提交,没提交的肯定不能让当前事务看见,

相反,如果这个数据版本的trx_id不在m_ids列表中,说明啥?说明生成数据版本的事务已经提交了,已经提交了就肯定能看了,所以这个数据版本对当前事务是可见的

但是trx_id小于min_trx_id就说明肯定是小于的,能看到

trx_id大于max_trx_id没启动呢还,就不用管了

每次修改数据,就记录修改的事务id到隐藏字段,然后生成一个版本,去记录到这个redo log的版本链当中,然后回滚指针指向版本链,通过对比redo_log

一个事务第一次读取之后,后面每次读取的数据都应该和第一次一样,维护一个数据多个版本,事务修改一次,就生成一个版本,不同事物读不同版本,读已提交的情况下,让事务去读已经提交的数据版本,这样就避免脏读了,

不可重复读的隔离界别下,让事务每次读到同一个版本的数据,这样每次读到的都一样了,避免了可重复读的问题,因此,把修改的数据版本,记录到一个undo log日志中,给表增加一个隐藏字段叫回滚指针回滚指针指向undo log日志,使用回滚指针把历史版本连接成一个链表,这样想读哪个版本,沿着链表一直找就好,一个事务来查数据,怎么知道我要去查哪个版本的数据,所以要给每个事务分配一个事务id,事务id自增分配,通过对比事务id大小,就能知道哪个事务创建的比较早,哪个事务创建的比较晚(然后再去记录哪些事务提交了),哪些事务没有提交,然后让提交的比较早的事务,不要看到提交比较晚的就好

给表增加一个隐藏字段

修改数据的事务id(trx_id):谁修改了他,就把对应事务id记录下来,

还需要read view(四个重要字段)

creator_trx_id:创建当前readview的事务id

m_ids:创建readview时,当前数据库中活跃且未提交的所有事务id

min_trx_id:创建readview时,数据库活跃且未提交的最小事务id

max_trx_id:创建readview时,应该分配给下一个新建事务的id

undo_log去记录数据版本,RedaView去判断数据版本对当前事务的可见性(MVCC)

如何实现各个隔离界别呢?

串行化:加锁

可重复读:第一次select的时候生成一个read view(用来判断数据版本对当前事务的可见性的)

可重复读每次都会复用第一次生成的review,也就是说当生成这个read view的时候,哪些版本对当前事务可见已经固定了,后续通过同一个readview去判断数据的可见性,因此,每次读都是同一批数据版本

可重复读通过复用readview加MVCC机制(为了

读未提交:每次select都会生成一个新的readview,每次读都生成了新的readview,每次读都能读到新提交的版本了,

幻读:可重复读如何尽量解决(分两种情况,1.快照读,在可重复读的隔离级别下,当执行普通的select语句时候会生成一个快照,通过MVCC去读,每次都读同一个数据版本,这就是快照读,普通select通过快照读去避免加锁,每次都去读快照,别的事务不去关心,读不到就不会幻读(但是不能永远读不到吧),比如你先开启了事务,别人后开启了事务,但是别人先插入id为1的数据

,但是你读不到,会以为id为1读数据不存在,那就去插入id为1的数据,但是不能插入啊,

插入这种操作比如读到新的数据,才能判断是否插入,这就是当前读, select for update或者select in share mode或者执行(增删改   insert   update ,delete都是当前读)的操作,当前读读的都是最新的数据,如果其他事务插入了,那不就还会产生幻读吗,执行当前读,mysql会使用临键锁,锁住数据和数据直接的间隙,我加锁了,你就不可以插入,只要我不让你插入修改啥的就好,

for update 当前读,加临键锁     (不让你插入,不就没有幻读了吗)(可以解决大部分问题)

下面一直阻塞,就报错误了,但是就是不能查,直到我去提交事务,

可重复读的隔离级别下,通过MVCC快照读,加上当前读加锁的方式避免幻读的,有极端情况,先快照读再当前读(如何解决)

比如这种(轻微诡异)

事务A(第一次查表里面没有,B提交之后,A查还是没有,但是当前读能查到)

事务B

 (重度诡异) A查找没有,B插入,A插入发现冲突了,存在,A在查找,还是没有

A但是能直接修改,改完去查就可以查到

(以上这种这么解决)一个事务操作某张表,另一个表不允许新增啥的,可以select for update加表锁,事务b插入数据就会阻塞(不让你插入就不会有幻读)

比如 where有索引列,就会加行锁,比如select 字段from 表 where id>=5 and id<=10 for update,这样就会使用临键锁,锁住5和10这两条记录,还会锁住5-10之间的间隙,即6,7,8,9都不能插入

分库分表

索引失效场景

对索引使用左或者左右模糊匹配

对索引使用函数

对索引进行表达式计算

对索引隐式类型转换

联合索引非最左匹配

Orderby和groupby 会用到联合索引吗

like如何避免全表查询

假如使用的是固定前缀  start% 这种情况,就可以通过索引,查找前缀,然后使用%

Mysql如何实现可重入锁

创建一个保存锁记录的表,出自MySQL面试题 | 小林coding

比如锁的名称,存储的当前持有锁的线程名称,锁的可重入次数

开启事务:判断当前的记录(锁)是否存在,不存在则去加锁,存在并且持有者是同一个线程,那么我就可重入update一下,给他更新

提交事务

解锁逻辑:

开启事务

执行SQL select 查找是否有记录,如果记录存在且持有者是同一个线程那么就去--,

如果记录存在,且持有者是同一个线程,且可重入的次数小于等于0,那么就去完全释放锁。 delete对应的锁名字就好

mysql的存储引擎

Innodb是mysql的默认引擎,具有ACID事务支持,行级锁,外键约束等支持(默认聚簇索引)

MyISAM:MyISAM是mysql的另一种常见存储引擎,具有较低的存储空间和内存消耗。不支持以上如acid等操作(非聚簇索引)

Memory:(不重要):性能高,但是不是持久的

冷备:定期将主数据中心的数据库文件备份到其他数据中心,冷备不提供实时服务,当丢失数据时候,可以通过冷备恢复数据,以保证数据安全

热备:通过数据库主从复制或者binlog订阅技术,对主数据中心进行实时备份,热备提供实时任务,当主数据中心不可用的时候,热备可以自动接管业务,保证业务不间断运行,用户端对主备切换无感知

同城机房:物理距离比较近,使用专线连接,虽然跨数据中心访问延迟比单个数据中心要大,但是可接受

异地机房:异地的数据中心物理距离远,网络延迟,就算你设置光纤一个来回也是10ms,中间还有路由器,交换机等设备,抖动很容易延迟到1s

应用在操作数据库时候,要求读写分离

原则就近访问

两地三中心

两个城市,三个数据中心,两个数据中心在一个城市并且同时提供服务,第三个做异地,灾备,防止数据丢失

抵御地域性故障,通过冷备份需要时间

索引适合数据量比较大,查询比较频繁,比如where,orderby,区分度高(身份证),字符串前缀,联合索引

打开慢查询日志(查找超过阈值,根据explain)

事务

事务原子性的实现undolog回滚性日志,连续N个连续的sql操作失败了一个通过undo log给前面的操作全部回滚,事务提交之后,如果数据库崩溃了,数据丢失了咋办,事务持久性,持久性通过redo_log,即便Mysql没有持久化到磁盘中,也能读取redo_log,所以可以说让Mysql有一个崩溃恢复的能力,redo_log怎么保证刷盘呢?(他怎么保证持久化)

隔离性怎么实现,需要用MVCC+锁配合undolog实现,(除了原子性,持久性隔离性之外,事务还要保证一致性,保证其他三个就能保证一致性)

不可重复读强调的是多次读取的数据值不同,幻读强调的是数据条数的增减

读已提交:只能读到其他事务已经提交的数据    -脏读其他事务没提交的你读取不到(本质每次select就生成一个新的read view,每次就能读到已经提交的数据版本

但是无法解决不可重复读和幻读的问题

可重复读默认隔离界别(第一次读会有快照,快照其他事务的修改,对于当前事务是不可见的,每次读快照,保证统一时间内,两次读到的数据是一样的,解决了不可重复读的问题

MVCC多版本并发控制,维护数据的多个版本,

数据库三大日志

什么是undo log,undo log有什么用,什么是redo log redolog有啥用,为啥要刷盘redolog,为啥不直接刷盘buffer pool

什么是bin log ,bin log有什么用,什么是两阶段提交,如何保证redo log和bin log的一致性,

MYSQL有事务,事务特性之一就是原子性,执行一系列SQL,要么全部成功,要么全部失败,后面的SQL失败了,已经执行了也要回滚

问题来了,我数据都修改了,怎么回滚到没有修改的版本呢?这个时候就需要保存数据的不同版本了,每修改一次,就把原始的数据版本保存下来,把不同版本,通过一个回滚指针串起来,

通过一个回滚指针串起来,这就叫undo log版本链也就是事务执行的过程中修改的数据,MYSQL会把旧的数据记录到undo log日志里面,如果事务正常提交,那就结束,如果因为异常或者执行了手动回滚,这种操作,那就通过undo log去找到旧版本的数据回滚,这也就是为啥说undo log可以保证事务的原子性, undo log第二个作用就是配合readView和表的隐藏字段去实现MVCC(MVCC执行普通select语句,就会对比事务id和readView,来查看这个数据版本,对当前事务是否可见,不可见,就沿着undo log版本链,继续查找当前事务可见的一个数据版本

每次从磁盘读写数据太慢了,写业务代码时候,查数据太慢了,咋办?

一般加一层缓存(CPU执行速度那么快,内存速度那么慢,那咋办,CPU三级缓存,(MYSQL设计了一个缓冲池叫buffer pool) MYSQL存数据以页为单位的,一个页16kb,每查询一条数据,就会把硬盘这一页的数据加载出来,把数据页放到buffer pool里面,问题来了,假如查一条数据,把数据放到缓存中不就行了。

为什么存储一个页的原因?(不至于把一个数据页的全部都读出来,放到这个buffer pool里面),程序的空间局部性原理(也就是说一个内存位置被访问了,意味着未来很有可能附近的内存位置都会被访问),因为代码里面大量使用数组这种连续结构,数组第一个位置访问了,第二,三个位置,都会被访问

同样的一些管理系统里面分页展示了很多数据,(如同抖音的一直下滑)

MYSQL一次把一个页的数据放到buffer pool中,对于连续取数据来说,命中率很高,利用了程序的一个空间局部性原理

后续取数据,先从buffer pool里面取,没有再去磁盘里面读,写数据也是先写入到buffer pool,但是不会立刻刷盘,而是把修改的页标记为脏页,然后由后台线程在某个时间内,把脏页刷盘

问题buffer pool是在内存的,他没有立即刷盘,MYSQL要是挂了,那么数据不久丢了吗?

因此有了redo log,MYSQL每次把某个磁盘页做了什么样子的修改,记录到redo log中,然后呢事务提交之后,就刷盘redo log,如果buffer pool中的数据未刷盘就宕机了, 就可以读取redo log来恢复数据,这就是为什么说redo log能够保证事务的持久性,让MYSQL能做到崩溃恢复,

为什么修改了buffer pool之后不直接刷盘呢? 而是去写redo log ,去刷盘redo log,

因为buffer pool刷盘是随机IO刷盘时候,需要找到某个磁盘页,然后去修改再去找另外的磁盘页,再去修改,本来磁盘就慢,随机IO更慢了

redo log只记录在哪个磁盘位置,做了怎么样的修改,刷盘的时候,只需要往redo log日志后面追加就好了,这个是顺序io,他不需要去找这个磁盘页,他磁头往一个方向去移动就可以了

这就是为什么redo log日志要去记录数据页的物理修改,而不是直接去记录数据,因此只要redo log一刷盘,即便MYSQL崩溃了,数据也可以恢复,事务的持久性就有了保证

redo log不是直接写入磁盘的,他也有自己的的缓存,叫redo log buffer

redo log会写入redo log buffer,然后统一把redo log buffer中的数据刷盘到磁盘中,MYSQL中,有一个参数叫,innodb_flash_log_and_trx_commit这个参数就是控制redo log一个刷盘时间的,如果参数的值为0,事务提交的时候会把redo log的数据放到redo log buffer但并不会进行刷盘危险-只是放入缓冲池,如果mysql宕机,redo log就会丢失数据)如果值为1,事务提交的时候,就会把redo log数据刷入磁盘,刷盘完成之后,才告诉客户端事务执行成功了,这样就能保证事务只要完成,即便MYSQL崩溃了,数据也不会丢失,一般情况下设置为1

值为2,事务提交,就会把redo log的数据写入操作系统的文件缓存里面,写入page cache,操作系统本身对文件也是有缓存的,缓存就是page cache,数据写入page cache之后,操作系统会在某一个时间,真正把这个数据写入磁盘中,只要操作系统不崩溃,就能保证持久性。但是假如电脑断电了,还是g.

bin log日志

redo log是否能做备份或者主从 ,redo log是循环写,日志空间的大小是固定的,全部写满就从头再开始写,边写边擦除,它只能记录事务提交之后,没有被刷盘的那个数据已经刷盘的,会从redo log中慢慢擦除掉的,所以redo log是事务级别的数据记录,而不是数据库级别的数据记录,只可以做那些断电,或者数据库故障导致buffer pool数据未刷盘的这种数据恢复,不能做数据库全量的数据恢复,要做备份恢复,或者要主从同步,只要你是数据库的变更,都会记录bin log日志,redolog是循环写,binlog是追加写,记录的是全量日志,redolog 可以理解为物理日志,在某个数据页上做什么修改binlog是逻辑日志,记录的内容类似于SQL语句本身,bin log非常适合做这种备份恢复,或者主从同步, bin log也有缓存 -bin logcache 执行时候会先把bin log日志,写入cache,提交的时候,就把bin log cache刷到磁盘中,

通过mysql日志设计-持久化就去搞日志,连续写的日志搞cache,先去写cache,再去异步刷盘通过日志就能做备份恢复,主从同步,(redis的rdb和aof也是这个道理)

假如redo log和bin log都要刷盘,一个刷盘成功,一个刷盘失败,两份日志不一样,咋办,为了解决两份日志之间一致性问题,mysql将redo log拆分成了prepare和commit,两阶段提交

假如写入redo log异常了,那么prepare异常了,redo log和bin log都没有,就直接回滚事务,事务没有提交成功

写入binlog异常,MYSQL根据redo log进行数据恢复的时候发现redo log处于prepare阶段,并没有对应的bin log日志,那么回滚事务

如果redo log设置commit时候异常了,MYSQL发现redo log是prepare阶段但能找到对应的bin log日志  bin log 和redo log就一致的的(MYSQL也会认为数据是完整的)所以直接提交事务,两阶段提交最终还是看bin log,只要bin log刷盘了那么就可以提交事务

redo log和bin log,

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

狗哥不是甜妹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值