mysql日志
例如,执行update时,更新语句涉及到了数据的更改,所以必不可少的需要引入日志模块。
redo log重做日志
redo log是InnoDB引擎特有的日志模块。
如果每一次的更新操作都需要写进磁盘,之后磁盘也要找到对应的那条记录,然后再更新,整个过程 IO 成本、查找成本都很高。
InnoDB引擎使用Write-Ahead Logging WAL
技术,它的关键点就是先写日志,再写磁盘。
具体来说,当有一条记录需要更新的时候, InnoDB 引擎就会先把记录写到 redo log 文件里面,并更新内存数据页,在更新内存写完 redo log 后,就返回给客户端,本次更新成功。 InnoDB 引擎会在适当的时候,将这个操作记录更新flush到磁盘数据里面,而这个更新往往是在系统比较空闲的时候做。
各种不同操作有不同的重做日志格式。
InnoDB 的 redo log 是固定大小的,比如可以配置为一组 4 个文件,每个文件的大小是 1GB 。从头开始写,写到末尾就又回到开头循环写,会擦除旧的记录,当然,擦除记录前会把它们更新到数据文件。
有了 redo log , InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个 能力称为 crash-safe
。
redo log 主要节省的是随机写磁盘的 IO 消耗(转成顺序写),而 change buffer(普通索引下更新数据时的一种机制) 主要节省的则是随机读磁盘的 IO 消耗。
脏页与干净页
当内存数据页跟磁盘数据页内容不一致的时候,我们称这个内存页为脏页。内存数据写入到磁盘后,内存和磁盘上的数据页的内容就一致了,称为干净页。
而刷脏页的过程由于会占用资源,可能会让你的更新和查询语句的响应时间长一些。
flush的时机
1.系统空闲的时候,或见缝插针地找时间,只要有机会就刷 “ 脏页 ” 。
2.正常关闭的情况。这时候, MySQL 会把内存的脏页都 flush 到磁盘上,这样下次 MySQL 启动的时候,就可以直接从磁盘上读数据,启动速度会很快。
3.redo log 满的时候,这时候系统会停止所有更新操作,把 checkpoint 往前推进, redo log 留出空间可以继续写。
这种情况是 InnoDB 要尽量避免的。因为出现这种情况 的时候,整个系统就不能再接受更新了,所有的更新都必须堵住。如果你从监控上看,这时候更新数会跌为 0 。
4.系统内存不足。当需要新的内存页,而内存不够用的时候,就要淘汰 一些数据页,空出内存给别的数据页使用。如果淘汰的是 “ 脏页 ” ,就要先将脏页写到磁盘。
这种情况其实是常态。
缓冲池(buffer pool)
InnoDB 用缓冲池( buffer pool )管理内存。
当要读入的数据页没有在内存的时候,就必须到缓冲池中申请一个数据页。这时候只能把最久不使用的数据页从内存中淘汰掉:如果要淘汰的是一个干净页,就直接释放出来复用;但如果是
脏页呢,就必须将脏页先刷到磁盘,变成干净页后才能复用。
刷脏页虽然是常态,但是出现以下这两种情况,都是会明显影响性能的:
- 一个查询要淘汰的脏页个数太多,会导致查询的响应时间明显变长;
- 日志写满,更新全部堵住,写性能跌为 0 ,这种情况对敏感业务来说,是不能接受的。
所以, InnoDB 需要有控制脏页比例的机制,来尽量避免上面的这两种情况。
InnoDB 刷脏页的控制策略
bin log归档日志、逻辑日志
binlog是数据库Server层自带的日志模块,所有引擎都可以使用。最开始 MySQL 里并没有 InnoDB 引擎。 MySQL 自带的引擎是 MyISAM ,但是 MyISAM 没有 crash-safe 的能力, binlog 日志只能用于归档。
由执行器生成某个操作的 binlog,记录本次修改的原始逻辑,说白了就是记录了修改数据的SQL语句。
这两种日志有以下三点不同。
- redo log 是 InnoDB 引擎特有的; binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。
- redo log 是物理日志,记录的是 “ 在某个数据页上做了什么修改 ” ; binlog 是逻辑日志,记录的 是这个语句的原始逻辑,比如 “ 给 ID=2 这一行的 c 字段加 1 ” 。
- redo log 是循环写的,空间固定会用完; binlog 是可以追加写入的。 “ 追加写 ” 是指 binlog 文件 写到一定大小后会切换到下一个,并不会覆盖以前的日志。
由于 redo log 和 binlog 是两个独立的逻辑,如果不用两阶段提交,要么就是先写完 redo log 再写 binlog ,或者采用反过来的顺序,数据库的状态就有可能和用它的日志恢复出来的库的
状态不一致。
通过mysqlbinlog可以解析查看binlog日志。
在今天中午12点的时候,发现上午10点执行了错误的SQL语句,想把数据库状态恢复到上午10点,错误语句执行之前。那么该怎么办呢?
数据恢复步骤如下:
首先你要拿到最近一次的备份库
拿到最近备份库开始到出错时候的所有binlog(binlog日志保留时间可以自定义)
使用binlog重放到错误发生之前。
Binlog有两种模式,statement 格式的话是记sql语句, row格式会记录行的内容,记两条,更新前和更新后都有。
binlog几大模式,一般采用row,因为遇到时间,从库可能会出现不一致的情况,但是row更新前后都有,会导致日志变大
最后2个参数,保证事务成功,日志必须落盘,这样,数据库crash后,就不会丢失某个事务的数据了。
binlog还不能去掉。
一个原因是,redolog只有InnoDB有,别的引擎没有。
另一个原因是,redolog是循环写的,不持久保存,binlog的“归档”这个功能,redolog是不具备的。
undo log回滚日志
主要用于事务的回滚。
每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值,通
过回滚操作,都可以得到前一个状态的值。
慢查询日志
set long_query_time=0;