MySQL(二)日志系统

更新语句的执行流程

MySQL可以恢复到半个月内任意一秒的状态. mysql> create table T(ID int primary key, c int);

这个表有一个主键ID和一个整型字段c,若要将ID=2这一行的值加1

mysql> update T set c=c+1 where ID=2;

首先执行语句前连接器要连接数据库,随后一个表上有更新时,跟这个表有关的查询缓存会失效,所以将表T上所有缓存结果都清空.分析器通过词法和语法解析直到这是一条更新语句,优化器决定使用ID这个索引,执行器负责具体执行,找到这一行,然后更新.

与查询流程不一样,更新流程还涉及两个重要的日志模块:redo log(重做日志)binlog(归档日志).

redo log

若每一次的更新操作都需要写进磁盘,然后磁盘也要找到对应的那条记录,然后再更新,整个过程IO成本、查找成本都很高.

WAL(Write-Ahead Logging)技术即先写日志,再些磁盘. 当有一条记录需要更新时,InnoDB引擎就会将记录先写到redo log并更新内存,此时更新就算完成了,同时引擎会在适当的时候,将这个操作记录更新到磁盘里面,而这个更新往往是在系统比较空闲的时候做.

InnoDB的redo log的大小是固定的,比如可以配置为一组4个文件,每个文件的大小是1GB,则共可以记录4GB的操作,从头开始写,写到末尾又回到开头循环写

write pos是当前记录的位置,一边写一边后移,checkpoint是当前要擦除的位置,也是往后推移并循环的,擦除记录前要将记录更新到数据文件.

write pos追上checkpoint则不能执行新的更新,要先擦掉一些记录,将checkpoint推进一下.

InnoDB通过redo log可以保证即使数据库发生异常重启,之前提交的记录也不会丢失,称为crash-safe.

binlog

redo log是InnoDB引擎特有的日志,而Server层也有自己的日志,称为binlog.

两者有如下不同:

  1. redo log是InnoDB引擎特有的,binlog是MySQl的Server层实现的,所有引擎都可以使用.
  2. redo log是物理日志,记录的是在某个数据页上做了什么修改,而binlog是逻辑日志,记录的是语句的原始逻辑,如’给ID=2行的c字段加1’.
  3. redo log是循环写的,空间固定会用完,binlog是可以追加写入的,追加写是指binlog文件写到一定大小后会切换值下一个,并不会覆盖以前的日志.

执行器和InnoDB引擎update语句的内部流程

  1. 执行器先找引擎取ID=2这一行,ID是主键,引擎直接用树搜索找到这一行,若ID=2这一行所在的数据页本来就在内存中,则直接返回给执行器,否则先从磁盘读入内存再返回.
  2. 执行器拿到引擎给的行数据之后,把这个值加1,得到新的一行数据,调用引擎接口写入这行新数据.
  3. 引擎将这行新数据更新到内存中,同时将这个更新操作记录到redo log里,此时redo log处于prepare状态,然后告知执行器执行完成了,随时可以提交事务.
  4. 执行器生成这个操作的binlog,并将binlog写入磁盘.
  5. 执行器调用引擎的提交事务接口,引擎将刚刚写入的redo log改成提交状态,更新完成.

redo log的写入拆成了两个步骤,preparecommit,即两阶段提交.

如何将数据库恢复至半个月内任意一秒的状态 binlog会记录所有逻辑操作,并且采用追加写的形式,如果DBA承诺半个月内可以恢复,则备份系统中一定会保存最近半个月的所有binlog,同时系统会定期做整库备份.

当需要恢复到指定的某一秒时,可以这样做:

  • 首先,找到最近的一次全量备份,若运气足够好,可能就是昨天的一个备份,从这个备份恢复到临时库.
  • 然后从备份的时间点开始,将备份的binlog依次取出来,重放到中午误删表的那个时刻.

这样临时库和误删之前的线上库一样了,然后可以将表数据从临时库取出来,按需恢复到线上库.

两阶段提交

为了让两份日志之间的逻辑一致.

由于redo logbinlog是两个独立的逻辑,若不用两阶段提交,要么就是先写完redo log再写binlog,或采用反过来的顺序.

假设当前ID=2的行,字段c的值是0,再假设执行update语句过程中,在写完第一个日志后,第二个日志还没有写完期间就发生了crash.

  1. 先写redo log 再写binlog

假设redo log写完,binlog还没有写完时,MySQL进程异常重启,根据redo log,即使系统崩溃,仍然可以将数据恢复过来,所以恢复后c的值为1.

但是由于binlog没写完就crash了,这时候binlog里面就没有记录这个语句,因此之后备份日志的时候,存起来的binlog里面就没有这条语句.

如果用binlog来恢复临时库的话,恢复出来的库与原库的值不同.

  1. 先写binlog后写redo log

如果再binlog写完之后crash,由于redo log还没写,崩溃恢复以后这个事务无效,所以这一行的值为0,但binlog里已经记录了将c从0改为1,若用binlog恢复临时库,与原库值不同.

redo logbinlog都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏bisal的个人杂货铺

MySQL系统运行状态实时监控(shell版本)

开始接触MySQL,还是和Oracle有些不一样的地方,需要逐步积累和学习,其中有一点不同,就是Oracle有一些数据字典,可以显示系统运行状态,但需要使用SQ...

30350
来自专栏Kevin-ZhangCG

并发出体验 -- 解决小规模并发下单的问题

  现在有这么一个业务场景,线上通过手机app下单买祈福灯,支付成功后,线下寺庙点亮。存在多个 用户同时选择同一个灯的情况出现,如下图。此时,正常情况应为一个用...

12080
来自专栏bisal的个人杂货铺

经典的运维脚本三步曲

无论是应用运维,还是数据库运维,均可以分为“人肉”-“自动化”-“智能化”阶段,其中自动化阶段,主要是将一些人做的操作,尤其是一些重复性操作,封装为程序,一方面...

18520
来自专栏bisal的个人杂货铺

JSP连接数据库大全

JSP连接数据库大全 一、jsp连接Oracle8/8i/9i数据库(用thin模式) testoracle.jsp如...

14520
来自专栏开发技术

Mycat - 高可用与负载均衡实现,满满的干货!

    和朋友去吃小龙虾,隔壁桌一个小女孩问妈妈:"妈妈,小龙虾回不了家,它妈妈会不会着急?" 她妈妈愣住了,我扒虾的手停下了,这么善良的问题,怎么下得了口。这...

85420
来自专栏bisal的个人杂货铺

一次SQL_ID和HASH_VALUE转换尝试引发的误区

http://blog.csdn.net/bisal/article/details/38919181

17310
来自专栏bisal的个人杂货铺

MySQL远程访问权限的设置

今儿有位同事提出,一套MySQL 5.6的环境,从数据库服务器本地登录,一切正常,可是若从远程服务器访问,就会报错,

38330
来自专栏雪雁的专栏

Docker最全教程——MongoDB容器化(十三)

上一节我们讲述了数据库容器化之持久保存数据,本节将讲诉MongoDB容器化实践,并且接下来将逐步讲解其他数据库(MySql、Redis等等)的容器化实践,然后将...

22530
来自专栏钱塘小甲子的博客

Tushare与Mysql在python下的演义

        首先给大家介绍的是一个很强大的财经数据接口库,是专门为python准备的哦。不过唯一的缺点是有比较大的数据缺失,这个库就是Tushare财经数据...

39630
来自专栏bisal的个人杂货铺

Windows环境安装MySQL ZIP Archive

这是之前写的几篇关于Linux环境下安装MySQL数据库的文章,包括5.7.19以及5.6这两个版本,

17740

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励