zoukankan      html  css  js  c++  java
  • 2 日志系统:一条sql更新语句是如何执行的?

    2 日志系统:一条sql更新语句是如何执行的?

    前面了解了一个查询语句的执行流程,并介绍了执行过程中涉及的处理模块,一条查询语句的执行过程一般是经过连接器、分析器、优化器、执行器等功能模块,最后达到engine

    这里分析一个update语句的流程

    mysql> create table T(ID int primary key, c int);

    更新语句

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

    查询语句的那一套流程,更新语句也是同样会走一遍

    执行语句前要先连接db--连接器的工作

    在一个表上有更新的时候,跟这个表有关的查询缓存会失效,所以这条语句就会把表T上所有缓存结果都清空--不建议使用查询缓存的原因

    接下来,分析器会通过词法和语法分析知道这是一条update语句,优化器决定使用id这个索引,然后执行器负责具体执行,找到这一行,然后update

    与查询流程不一样的,更新流程还涉及两个重要的日志模块:redo logbinlog

    redo log

    mysql里,如果每一次的更新操作都需要写进磁盘,然后磁盘也要找到那条对应的记录,然后再更新,整个过程io成本、查找成本都很高,为了解决这个问题,在mysql里使用WALwrite-ahead loggin,日志先行,关键点就是先写日志、再写磁盘。

       当有一条记录需要更新的时候,innodb引擎就会先把记录写到redo log,并更新内存,这个时候更新就算完成了。同时,innodb引擎会在适当的时候,将这个记录更新到磁盘里面。

    Innodbredo log是固定大小,从头开始,写到末尾就又回到开头循环写,有了redo loginnodb就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个功能称为crash-safe

    binlog

    mysql整体来看,一块是server层,主要是mysql功能层面的事情;另一块是引擎层,负责存储相关的具体事宜,redo log就是innodb特有的日志,而server层的日志,就是binlog

    两种日志的不同点

    --1 redo loginnodb引擎特有的,binlogmysql server层实现的,所有引擎都可以使用。

    --2 redo log是物理日志,记录的是”在某个数据页上做了什么修改”binlog是逻辑日志,记录的是这个语句的原始逻辑。

    --3 redo log是循环写的,空间固定;binlog是可以追加写入的,binlog文件写到一定大小后会切换到下一个,并不会覆盖之前的日志

    更新update的流程

    --1 执行器找到engineid=2的这一行,id是主键,engine直接用树搜索找到这一行,如果id=2这一行所在的数据本来就在内存中,就直接返回给执行器,否则,需要先从磁盘读入内存,然后再返回。

    --2 执行器拿到engine给的行数据,把这个值加上1,比如是n>n+1,得到新的一行数据,在调用引擎接口写入这行新数据

    --3 engine将这行新数据更新到内存中,同时将这个更新操作记录到redo log里面,此时redo log处于prepare状态,然后告知执行器完成了,随时可以提交事务

    --4 执行器生成这个操作的binlog,并把binlog写入磁盘

    --5 执行器调用引擎的提交事务接口,engine把刚刚写入的redo log改成提交(commit)状态,更新完成。

    两阶段提交

    怎样让数据库恢复到7天内任意一秒的状态?

    binlog会记录所有的逻辑操作,并且是采用追加写的形式,如果保存了最近一个月的binlog,同时系统有定期的整库备份,当需要恢复到指定的某一秒时,比如某条下午两点发现中午十二点有一次误删表,需要找回数据,可以这么做

    --1 找到最近一次的全备份,如果运气好,可能就是昨晚上的一个备份,从这个备份恢复到临时库

    --2 从备份的时间点开始,将备份的binlog依次取出来,重放到中午误删表之前的那个时刻。

    这样临时库就跟误删之前的线上一样,然后可以把表数据从临时库取出来,按需要恢复到线上库去。

    由于redo logbinlog是两个独立的逻辑,如果不用两阶段提交,要么是先写完redo log再写binlog,或者反过来的顺序,看看有什么问题

    --1 先写redo log后写binlog。假设redo log完成,binlog还没有写完,mysql异常重启,由于redo log写完之后,即使系统崩溃,已让能够把数据恢复。

    但是由于binlog没写完就crash,这时候binlog没有这条update语句,之后备份日志的时候,存起来的binlog就没有这条语句,如果用binlog恢复的话,就会丢失之前的更新。

    --2先写binlog后写redo log。如果在binlog之后carsh,还没来得及写redo log,崩溃恢复后这个update更新就无效,但是binlog里面已经记录了更新,这样用binlog来进行恢复就会导致不一致,同时也会导致备库的不一致。

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

    redo log用于保证crash-safe的能力,innodb_flush_log_at_trx_commit=1表示每次事务的redo log都直接持久化到磁盘,建议设置为1sync_binlog=1,表示每次事务的binlog都持久化到磁盘,也建议设置为1.--1模式

  • 相关阅读:
    java 整合 ssm (spring+ springmvc+ mybatis)
    java spring 事物 ( 已转账为例 ) 基于 aop 注解
    java spring 事物 ( 已转账为例 ) 基于 xml 配置,事务类型说明
    JAVA Spring 面向切面编程 基本案例(AOP)
    java websocket 简单的聊天室
    java websocket 实现简单的前后端即时通信
    js 通过文件输入框读取文件为 base64 文件, 并借助 canvas 压缩 FileReader, files, drawImage
    js 使用 XMLHttpRequest 请求发送 formdata 对象,从而上传文件
    html5 canvas ( 创建图形对象 ) createImageData
    编写Shell脚本的最佳实践
  • 原文地址:https://www.cnblogs.com/yhq1314/p/11011219.html
Copyright © 2011-2022 走看看