mysql性能优化innodb之日志文件(代码片段)

歪桃 歪桃     2023-02-21     312

关键词:

1.MySQL日志记录文件

1.1.回顾SQL语句的执行

在上一篇文章我中,我们着重的介绍了SQL语句执行的一个过程。
MySQL性能优化(一)MySQL中SQL语句是如何执行的

1.2.InnoDB内存结构:缓冲池

InnoDB存储引擎中有一个非常重要的放在内存里的组件,就是缓冲池(Buffer Pool),这里面会缓存很多的数据,以便于以后在查询的时候,万一你要是内存缓冲池里有数据,就可以不用去查磁盘了。

引擎要执行更新语句的时候 ,比如对“id=1”这一行数据,他其实会先将“id=1”这一行数据看看是否在缓冲池里,如果不在的话,那么会直接从磁盘里加载到缓冲池里来,而且接着还会对这行记录加独占锁。

1.3.记录日志:Undo和Redo

1.3.1.Undo日志文件:记录数据修改前的值

接着下一步,假设“id=1”这行数据的name原来是“zhangsan”,现在我们要更新为“hutao”,那么此时我们得先把要更新的原来的值“zhangsan”和“id=1”这些信息,写入到undo日志文件中去。

在事务提交之前我们都是可以对数据进行回滚的,也就是把你更新为“hutao”的值回滚到之前的“zhangsan”去。考虑到未来可能要回滚数据的需要,这里会把你更新前的值写入undo日志文件

更新缓冲池中的缓存数据

当我们把要更新的那行记录从磁盘文件加载到缓冲池,同时对他加锁之后,而且还把更新前的旧值写入undo日志文件之后,我们就可以正式开始更新这行记录了,更新的时候,先是会更新缓冲池中的记录,此时这个数据就是脏数据了。

这里所谓的更新内存缓冲池里的数据,意思就是把内存里的“id=1”这行数据的name字段修改为“hutao”
那么为什么说此时这行数据就是脏数据了呢?
因为这个时候磁盘上“id=1”这行数据的name字段还是“zhangsan”,但是内存里这行数据已经被修改了,所以就会叫他是脏数据。

1.3.2.Redo日志文件:记录数据即将修改值

redo即redo日志,记录数据库变化的日志。现在已经把内存里的数据进行了修改,但是磁盘上的数据还没修改,那么此时万一MySQL所在的机器宕机了,必然会导致内存里修改过的数据丢失,这可怎么办呢?
Redo对内存所做的修改写入到一个Redo Log Buffer里去,这也是内存里的一个缓冲区,是用来存
放redo日志的。redo日志其实是用来在MySQL突然宕机的时候,用来恢复你更新过的数据。

如果还没提交事务,MySQL宕机了怎么办
只有当你提交事务之后,SQL语句才算执行结束。所以这里我们都知道,到目前为止,其实还没有提交事务,那么此时如果MySQL崩溃,必然导致内存里Buffer Pool中的修改过的数据都丢失,同时你写入Redo Log Buffer中的redo日志也会丢失。

那么此时数据丢失要紧吗?其实是不要紧的,因为你一条更新语句,没提交事务,就代表他没执行成功,此时MySQL宕机虽然导致内存里的数据都丢失了,但是你会发现,磁盘上的数据依然还停留在原样子。也就是说,“id=1”的那行数据的name字段的值还是老的值,“zhangsan”,所以此时你的这个事务就是执行失败了,没能成功完成更新,你会收到一个数据库的异常。然后当mysql重启之后,你会发现你的数据并没有任何变化。所以此时如果mysql宕机,不会有任何的问题。

1.3.3.Undo和Redo的区别(记录、前滚、回滚)

记录数据区别:

  1. redo记录:记录数据库变化的日志,只要你修改了数据块那么就会记录redo信息,当然nologging除外
  2. undo记录:是指数据库为了保持读一致性,存储的历史数据,也就是修改前的数据。

前滚与回滚:

  1. 前滚:当实例崩溃时,可以使用redo从以前正常的点前滚到崩溃点。当数据库回到一致性检查点时,相当于之后什么都没有发生过,数据全被清空了。数据库只好根据redo模拟人的操作,使用redo里的信息重做(use redo log to redo),构造undo块,表块,索引块等
  2. 回滚:构造的表数据块中,有已修改的脏数据但未提交,就需要利用前滚中构造的undo数据块里的信息来undo撤销还原。

1.3.4.提交事务:Redo日志写入磁盘(刷盘策略)

接着我们想要提交一个事务了,此时就会根据一定的策略把redo日志从redo log buffer里刷入到磁盘文件里去。此时这个策略是通过innodb_flush_log_at_trx_commit来配置的(可以配置0、1、2)。

1.3.4.1.trx_commit = 0

提交事务的时候,不会把redo log buffer里的数据刷入磁盘文件的,此时可能你都提交事务了,结果mysql宕机了,然后此时内存里的数据全部丢失。相当于你提交事务成功了,但是由于MySQL突然宕机,导致内存中的数据和redo日志都丢失了,我们看下图:

1.3.4.2.trx_commit = 1

提交事务的时候,就必须把redo log从内存刷入到磁盘文件里去,只要事务提交成功,那么redo log就
必然在磁盘里了,我们看下图:

那么只要提交事务成功之后,redo日志一定在磁盘文件里,此时你肯定会有一条redo日志记录了,“哪个数据做了一个什么修改,比如name字段修改为hutao了”。然后哪怕此时buffer pool中更新过的数据还没刷新到磁盘里去,此时内存里的数据是已经更新过的“name=hutao”,然后磁盘上的数据还是没更新过的“name=zhangsan”。我们看下图,提交事务之后,可能处于的一个状态。

此时如果说提交事务后处于上图的状态,然后mysql系统突然崩溃了,此时会如何?会丢失数据吗?
肯定不会啊,因为虽然内存里的修改成name=hutao的数据会丢失,但是redo日志里已经说了,对某某数据做了修改name=hutao。所以此时mysql重启之后,他可以根据redo日志去恢复之前做过的修改,我们看下图。

1.3.4.3.trx_commit = 2

提交事务的时候,把redo日志写入磁盘文件对应的os cache缓存里去,而不是直接进入磁盘文件,可
能1秒后才会把os cache里的数据写入到磁盘文件里去。
这种模式下,你提交事务之后,redo log可能仅仅停留在os cache内存缓存里,没实际进入磁盘文件,万一此时你要是机器宕机了,那么os cache里的redo log就会丢失,同样会让你感觉提交事务了,结果数据丢了,看下图。

1.3.4.4.Redo日志3种刷盘策略对比

选择0的话,可能你提交事务之后,mysql宕机,那么此时redo日志没有刷盘,导致内存里的redo日志丢失,你提交的事务更新的数据就丢失了;

选择1的话,也就是说,提交事务的时候,redo日志必须是刷入磁盘文件里的。这样可以严格的保证提交事务之后,数据是绝对不会丢失的,因为有redo日志在磁盘文件里可以恢复你做的所有修改。

选择2的话,如果机器宕机,虽然之前提交事务的时候,redo日志进入os cache了,但是还没进入磁盘文
件,此时机器宕机还是会导致os cache里的redo日志丢失。

所以对于数据库这样严格的系统而言,一般建议redo日志刷盘策略设置为1,保证事务提交之后,数据绝对不能丢失。

1.4.归档日志:binlog

1.4.1.binlog介绍

redo log,他是一种偏向物理性质的重做日志,因为他里面记录的是类似这样的东西,“对哪个数据页中的什么记录,做了个什么修改”。而且redo log本身是属于InnoDB存储引擎特有的一个东西。

而binlog叫做归档日志,他里面记录的是偏向于逻辑性的日志,类似于“对users表中的id=1的一行数据做了更新操作,更新以后的值是什么”
binlog不是InnoDB存储引擎特有的日志文件,是属于mysql server自己的日志文件。

1.4.2.提交事务:写入binlog

在我们提交事务的时候,会把redo log日志写入磁盘文件中去。然后其实在提交事务的时候,我们同时还会把这次更新对应的binlog日志写入到磁盘文件中去,如下图所示:

大家可以在这个图里看到一些变动,就是我把跟InnoDB存储引擎进行交互的组件加入了之前提过的执行器这个组件,他会负责跟InnoDB进行交互,包括从磁盘里加载数据到Buffer Pool中进行缓存,包括写入undo日志,包括更新Buffer Pool里的数据,以及写入redo log buffer,redo log刷入磁盘,写binlog,等等
实际上,执行器是非常核心的一个组件,负责跟存储引擎配合完成一个SQL语句在磁盘与内存层面的全部数据更新操作。而且我们在上图可以看到,我把一次更新语句的执行,拆分为了两个阶段,上图中的1、2、3、4几个步骤,其实本质是你执行这个更新语句的时候干的事。然后上图中的5和6两个步骤,是从你提交事务开始的,属于提交事务的阶段了。

1.4.3.binlog刷盘策略分析

对于binlog日志,其实也有不同的刷盘策略,有一个sync_binlog参数可以控制binlog的刷盘策略。

1.4.3.1.sync_binlog = 0

他的默认值是0,此时你把binlog写入磁盘的时候,其实不是直接进入磁盘文件,而是进入os cache内存缓存。所以跟之前分析的一样,如果此时机器宕机,那么你在os cache里的binlog日志是会丢失的。

1.4.3.2.sync_binlog = 1

如果要是把sync_binlog参数设置为1的话,那么此时会强制在提交事务的时候,把binlog直接写入到磁盘文件里去,
那么这样提交事务之后,哪怕机器宕机,磁盘上的binlog是不会丢失的,如下图所示

1.5.基于binlog和redo log 的commit标记

当我们把binlog写入磁盘文件之后,接着就会完成最终的事务提交,此时会把本次更新对应的binlog文件名称和这次更新的binlog日志在文件里的位置,都写入到redo log日志文件里去,同时在redo log日志文件里写入一个commit标记。在完成这个事情之后,才算最终完成了事务的提交,我们看下图的示意:

最后在redo日志中写入commit标记有什么意义呢?他其实是用来保持redo log日志与binlog日志一致的
举个例子,假设我们在提交事务的时候,一共有上图中的5、6、7三个步骤,必须是三个步骤都执行完毕,才算是提交了事务。那么在我们刚完成步骤5的时候,也就是redo log刚刷入磁盘文件的时候,mysql宕机了,此时怎么办?
这个时候因为没有最终的事务commit标记在redo日志里,所以此次事务可以判定为不成功。不会说redo日志文件里有这次更新的日志,但是binlog日志文件里没有这次更新的日志,不会出现数据不一致的问题。如果要是完成步骤6的时候,也就是binlog写入磁盘了,此时mysql宕机了,怎么办?同理,因为没有redo log中的最终commit标记,因此此时事务提交也是失败的。必须是在redo log中写入最终的事务commit标记了,然后此时事务提交成功,而且redo log里有本次更新对应的日志,binlog里也有本次更新对应的日志 ,redo log和binlog完全是一致的。

1.6.IO线程将内存更新后的脏数据刷回磁盘

现在我们假设已经提交事务了,此时更新

update users set name='hutao' where id=1

他已经把内存里的buffer pool中的缓存数据更新了,同时磁盘里有redo日志和binlog日志,都记录了把我们指定的“id=1”这行数据修改了“name=‘hutao’”。此时我们会思考一个问题了,但是这个时候磁盘上的数据文件里的“id=1”这行数据的name字段还是等于zhangsan这个旧的值啊!

所以MySQL有一个后台的IO线程,会在之后某个时间里,随机的把内存buffer pool中的修改后的脏数据给刷回到磁盘上的数据文件里去。

当上图中的IO线程把buffer pool里的修改后的脏数据刷回磁盘的之后,磁盘上的数据才会跟内存里一样,都是name=hutao这个修改以后的值了!在你IO线程把脏数据刷回磁盘之前,哪怕mysql宕机崩溃也没关系,因为重启之后,会根据redo日志恢复之前提交事务做过的修改到内存里去,就是id=1的数据的name修改为了hutao,然后等适当时机,IO线程自然还是会把这个修改后的数据刷到磁盘上的数据文件里去的。

《mysql系列-innodb引擎14》文件-日志文件-错误日志(代码片段)

...的运行状态进行诊断,从而更好的进行数据库层面的优化。错误日志  错误日志文件对MySQL的启动、运行、关闭过程进行记录。MyS 查看详情

《mysql系列-innodb引擎18》文件-日志文件-查询日志(代码片段)

...的运行状态进行诊断,从而更好的进行数据库层面的优化。查询日志  查询日志记录了所有对MySQL数据库请求的信息,无论这些请求是否得到了正确的执行。默认文件名为:hostname.log。#1.查询日志未开启mysql>showvar... 查看详情

《mysql系列-innodb引擎14》文件-日志文件-错误日志(代码片段)

...的运行状态进行诊断,从而更好的进行数据库层面的优化。错误日志  错误日志文件对MySQL的启动、运行、关闭过程进行记录。MySQLDBA在遇到问题时应该首先查看该文件以便定位问题。该文件不仅记录了所有的错误信息࿰... 查看详情

性能优化之异步日志(代码片段)

...ender打印日志。     那么使用了AsyncAppender,会不会性能就好了,就不会阻塞业务流程了,会不会丢失日志呢,我们来看一下logback的实现。                                        查看详情

性能优化之异步日志(代码片段)

...ender打印日志。     那么使用了AsyncAppender,会不会性能就好了,就不会阻塞业务流程了,会不会丢失日志呢,我们来看一下logback的实现。                                        查看详情

高性能mysql卷一之架构分析(代码片段)

高性能MySQL卷一之架构分析Mysql架构优化与执行并发控制读写锁锁粒度表锁行级锁事务隔离级别死锁事务日志MYSQL中的事务自动提交在事务中混合使用存储引擎隐式和显示锁定多版本并发控制存储引擎InnoDB存储引擎MyISAM存储引擎转... 查看详情

mysql参数调优(2)之设置重做日志文件的大小innodb_log_file_size

...写入操作,那么选择合适的innodb_log_file_size值对提升MySQL性能很重要。然而设置太大了,就会增加恢复的时间,因此在MySQL崩溃或者突然断电等情况会令MySQL服务器花很长时间来恢复。由于事务日志相当于一个写缓冲,而小日志文... 查看详情

《mysql系列-innodb引擎23》文件-innodb存储引擎文件-重做日志文件(代码片段)

InnoDB存储引擎文件  之前介绍的文件都是MySQL数据库本身的文件,和存储引擎无关。除了这些文件外,每个表存储引擎都有其自己独有的文件。本节将具体介绍与InnoDB存储引擎密切相关的文件,这些文件包括重做日... 查看详情

大白话系统mysql学习总结之缓冲池(bufferpool)的设计原理和管理机制(代码片段)

...InnoDB存储引擎中最重要的组件。因为为了提高MySQL的并发性能,使用到的数据都会缓存在缓冲池中,然后所有的增删改查操作都将在缓冲池中执行。通过这种方式,保证每个更新请求,尽量就是只更新内存,然后往磁盘顺序写日... 查看详情

java回顾之mysql性能优化

java回顾之mysql性能优化一、慢查询日志慢查询日志,可以监控运行效率低下的sql语句,这样就可以知道是哪个sql语句拖累了整体的效率--查看慢查询日志开启情况showvariableslike‘%query%‘;开启慢查询setglobalslow_query_log=on;修改监控sql... 查看详情

《mysql系列-innodb引擎19》文件-日志文件-二进制日志(代码片段)

...的运行状态进行诊断,从而更好的进行数据库层面的优化。二进制日志  二进制日志(binarylog)记录了对MySQL数据库执行更改的所有操作,但是不包括select和show这类操作,因为该类操作本身对数据没有修改。然而,... 查看详情

mysql优化(代码片段)

...08;适合高并发,行锁:每条数据都要锁,所以性能就降低了)MyISAM:性能优 查看详情

mysql优化(代码片段)

...08;适合高并发,行锁:每条数据都要锁,所以性能就降低了)MyISAM:性能优 查看详情

mysql相关的各种类型文件(代码片段)

...擎通用日志二进制日志套接字文件pid文件表结构定义文件Innodb存储引擎的文件表空间文件redo日志文件大汇总Mysql和Innodb启动和运行过程中涉及到了一堆文件,这些文件主要有:参数文件:指定相关初始化参数日志文件:常见的有... 查看详情

mysql之性能分析(mysqlreport工具)(代码片段)

...、mysqlreport作用进行MySQL的配置优化,首先必须找出MySQL的性能瓶颈所在;而SHOWSTATUS输出的报告正是用来计算性能瓶颈的参考数据。mysqlreport不像SHOWSTATUS那样简单的罗列数据,而是对这些参考数据加以融合计算,整理成一个个优... 查看详情

mysql体系结构(代码片段)

...QL体系结构MySQL体系结构软件构成存储引擎层(MyISAM与InnoDB引擎)存储层存储层如何保存数据?MyISAM引擎InnoDB引擎MySQL数据库物理文件日志文件错误日志文件.err二进制日志文件binlog.log中继日志relaylog一般查询日志慢查... 查看详情

mysql视频教程推荐,性能优化之关于像素管道及优化(代码片段)

JS/CSS(代码变动)我们使用 JS 来改变样式是最为常见的,对于通过 JS 来改变动画,有以下几点需要注意:动画效果尽量使用 requestAnimationFrame 而不是使用 setTimeout 或者 setInterval由于 JS 是单线程运行... 查看详情

庖丁解innodb之redolog(代码片段)

...时,还能以灵活的刷盘策略来充分利用磁盘顺序写的性能,会记录REDO和UNDO日志,即ARIES方法。本文将重点介绍REDOLOG的作用,记录的内容,组织结构,写入方式等内容,希望读者能够更全面准确的理解RE... 查看详情