7. Innodb底层原理与Mysql日志机制深入剖析

news/2025/9/20 12:56:38/文章来源:https://www.cnblogs.com/fei1010/p/19102316

7.1 Mysql的内部结构

大体来说,MySQL可以分为Server层和存储引擎层两部分。

7.1.1 Server层

主要包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内
置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视
图等。

(1)连接器

我们知道由于MySQL是开源的,他有非常多种类的客户端:navicat,mysql front,jdbc,SQLyog等非常丰富的客
户端,包括各种编程语言实现的客户端连接程序,这些客户端要向mysql发起通信都必须先跟Server端建立通信连
接,而建立连接的工作就是有连接器完成的.

第一步,你会先连接到这个数据库上,这时候接待你的就是连接器。连接器负责跟客户端建立连接、获取权限、
维持和管理连接。连接命令一般是这么写的:

[root@192 ~]# mysql ‐h host[数据库地址] ‐u root[用户] ‐p root[密码] ‐P 3306

连接命令中的 mysql 是客户端工具,用来跟服务端建立连接。在完成经典的 TCP 握手后,连接器就要开始认证
你的身份,这个时候用的就是你输入的用户名和密码。

这就意味着,一个用户成功建立连接后,即使你用管理员账号对这个用户的权限做了修改,也不会影响已经存在
连接的权限。修改完成后,只有再新建的连接才会使用新的权限设置。

(2)查询缓存

MySQL 拿到一个查询请求后,会先到查询缓存看看,之前是不是执行过这条语句。之前执行过的语句及其结果
可能会以 key-value 对的形式,被直接缓存在内存中。key 是查询的语句,value 是查询的结果。如果你的查询能够
直接在这个缓存中找到 key,那么这个 value 就会被直接返回给客户端。

因为查询缓存往往弊大于利。查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查询缓存都会
被清空。因此很可能你费劲地把结果存起来,还没使用呢,就被一个更新全清空了。对于更新压力大的数据库来说,
查询缓存的命中率会非常低。

一般建议大家在静态表里使用查询缓存,什么叫静态表呢?就是一般我们极少更新的表。比如,一个系统配置
表、字典表,那这张表上的查询才适合使用查询缓存。好在 MySQL 也提供了这种“按需使用”的方式。你可以将
my.cnf参数 query_cache_type 设置成 DEMAND。

# my.cnf 文件
#query_cache_type有3个值 0代表关闭查询缓存OFF,1代表开启ON,2(DEMAND)代表当sql语句中有SQL_CACHE关键
词时才缓存
query_cache_type=2
show global variables like "%query_cache_type%"; # 检查查询缓存是否开启
select SQL_CACHE * from test where ID=5; # 模式2时使用查询缓存的语句

mysql 8.0已经移除了查询缓存功能

(3)分析器

如果没有命中查询缓存,就要开始真正执行语句了。首先,MySQL 需要知道你要做什么,因此需要对 SQL 语句做解
析。

  • 词法分析

分析器先会做“词法分析”。你输入的是由多个字符串和空格组成的一条 SQL 语句,MySQL 需要识别出里面的字符
串分别是什么,代表什么。
MySQL 从你输入的"select"这个关键字识别出来,这是一个查询语句。它也要把字符串“T”识别成“表名 T”,把
字符串“ID”识别成“列 ID”。

  • 语法分析

根据词法分析的结果,语法分析器会根据语法规则,判断你输入的这个
SQL 语句是否满足 MySQL 语法。
如果你的语句不对,就会收到“You have an error in your SQL syntax”的错误提醒。

SQL语句经过分析器分析之后,会生成一个这样的语法树

语法树

至此我们分析器的工作任务也基本圆满了。

(4)优化器

经过了分析器,MySQL 就知道你要做什么了。在开始执行之前,还要先经过优化器的处理。
优化器是在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联(join)的时候,决定各
个表的连接顺序;以及一些mysql自己内部的优化机制。

(5)执行器

开始执行的时候,要先判断一下你对这个表 T 有没有执行查询的权限,如果没有,就会返回没有权限的错误,如
下所示 (在工程实现上,如果命中查询缓存,会在查询缓存返回结果的时候,做权限验证)。

select * from test where id=10;

如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。

7.1.2 存储引擎层

存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持 InnoDB、MyISAM、Memory 等多个存储引
擎。现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开始成为了默认存储引擎。也就是说如果我们在
create table时不指定表的存储引擎类型,默认会给你设置存储引擎为InnoDB。

7.2 Innodb底层原理与Mysql日志机制

7.2.1 redo log重做日志关键参数

show variables like '%innodb_log_buffer_size%'; # redo log buffer大小参数,默认16M ,最大值是4096M,最小值为1M。
show variables like '%innodb_log_group_home_dir%'; # redo log文件存储位置参数,默认值为"./",即innodb数据文件存储位置,其
中的 ib_logfile0 和 ib_logfile1 即为redo log文件。
show variables like '%innodb_log_files_in_group%'; # redo log文件的个数,命名方式如: ib_logfile0, iblogfile1... iblogfileN。默认2
个,最大100个。
show variables like '%innodb_log_file_size%'; # 单个redo log文件大小,默认值为48M。最大值为512G,注意最大值指的是整个 redo
log系列文件之和,即(innodb_log_files_in_group * innodb_log_file_size)不能大于最大值512G。

7.2.2 redo log 写入磁盘过程分析

redo log 从头开始写,写完一个文件继续写另一个文件,写到最后一个文件末尾就又回到第一个文件开头循环写,如
下面这个图所示。

image-20250920123215836

write pos 是当前记录的位置,一边写一边后移,写到第 3 号文件末尾后就回到 0 号文件开头。
checkpoint 是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件里。

write pos 和 checkpoint 之间的部分就是空着的可写部分,可以用来记录新的操作。如果 write pos 追上
checkpoint,表示redo log写满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把 checkpoint 推进一
下。

innodb_flush_log_at_trx_commit:这个参数控制 redo log 的写入策略,它有三种可能取值:

  • 设置为0:表示每次事务提交时都只是把 redo log 留在 redo log buffer 中,数据库宕机可能会丢失数
    据。
  • 设置为1(默认值):表示每次事务提交时都将 redo log 直接持久化到磁盘,数据最安全,不会因为数据库
    宕机丢失数据,但是效率稍微差一点,线上系统推荐这个设置。
  • 设置为2:表示每次事务提交时都只是把 redo log 写到操作系统的缓存page cache里,这种情况如果数
    据库宕机是不会丢失数据的,但是操作系统如果宕机了,page cache里的数据还没来得及写入磁盘文件的话就
    会丢失数据。

7.2.3 binlog二进制归档日志

binlog二进制日志记录保存了所有执行过的修改操作语句,不保存查询操作。如果 MySQL 服务意外停止,可通过二
进制日志文件排查,用户操作或表结构操作,从而来恢复数据库数据。

启动binlog记录功能,会影响服务器性能,但如果需要恢复数据或主从复制功能,则好处则大于对服务器的影响。

# 查看binlog相关参数
show variables like '%log_bin%';

MySQL5.7 版本中,binlog默认是关闭的,8.0版本默认是打开的。log_bin的值是OFF就代表binlog是关闭状
态,打开binlog功能,需要修改配置文件my.ini(windows)或my.cnf(linux),然后重启数据库。
在配置文件中的[mysqld]部分增加如下配置

# log‐bin设置binlog的存放位置,可以是绝对路径,也可以是相对路径,这里写的相对路径,则binlog文件默认会放在
data数据目录下
log‐bin=mysql‐binlog
# Server Id是数据库服务器id,随便写一个数都可以,这个id用来在mysql集群环境中标记唯一mysql服务器,集群环
境中每台mysql服务器的id不能一样,不加启动会报错
server‐id=1
# 其他配置
binlog_format = row # 日志文件格式,下面会详细解释
expire_logs_days = 15 # 执行自动删除binlog日志文件的天数, 默认为0, 表示不自动删除
max_binlog_size = 200M # 单个binlog日志文件的大小限制,默认为 1GB

重启数据库后我们再去看data数据目录会多出两个文件,第一个就是binlog日志文件,第二个是binlog文件的索引文
件,这个文件管理了所有的binlog文件的目录。

当然也可以执行命令查看有多少binlog文件

show binary logs;
log_bin:binlog日志是否打开状态
log_bin_basename:是binlog日志的基本文件名,后面会追加标识来表示每一个文件,binlog日志文件会滚动增加
log_bin_index:指定的是binlog文件的索引文件,这个文件管理了所有的binlog文件的目录。
sql_log_bin:sql语句是否写入binlog文件,ON代表需要写入,OFF代表不需要写入。如果想在主库上执行一些操作,
但不复制到slave库上,可以通过修改参数sql_log_bin来实现。比如说,模拟主从同步复制异常。

7.2.4 binlog 的日志格式

用参数 binlog_format 可以设置binlog日志的记录格式,mysql支持三种格式类型:
STATEMENT:基于SQL语句的复制,每一条会修改数据的sql都会记录到master机器的bin-log中,这种
方式日志量小,节约IO开销,提高性能,但是对于一些执行过程中才能确定结果的函数,比如UUID()、
SYSDATE()等函数如果随sql同步到slave机器去执行,则结果跟master机器执行的不一样。
ROW:基于行的复制,日志中会记录成每一行数据被修改的形式,然后在slave端再对相同的数据进行修
改记录下每一行数据修改的细节,可以解决函数、存储过程等在slave机器的复制问题,但这种方式日志量较
大,性能不如Statement。举个例子,假设update语句更新10行数据,Statement方式就记录这条update语
句,Row方式会记录被修改的10行数据。
MIXED:混合模式复制,实际就是前两种模式的结合,在Mixed模式下,MySQL会根据执行的每一条具
体的sql语句来区分对待记录的日志形式,也就是在Statement和Row之间选择一种,如果sql里有函数或一些
在执行时才知道结果的情况,会选择Row,其它情况选择Statement,推荐使用这一种。

7.2.5 binlog写入磁盘机制

binlog写入磁盘机制主要通过 sync_binlog 参数控制,默认值是 0。

  • 为0的时候,表示每次提交事务都只 write 到page cache,由系统自行判断什么时候执行 fsync 写入磁
    盘。虽然性能得到提升,但是机器宕机,page cache里面的 binlog 会丢失。
  • 也可以设置为1,表示每次提交事务都会执行 fsync 写入磁盘,这种方式最安全。
  • 还有一种折中方式,可以设置为N(N>1),表示每次提交事务都write 到page cache,但累积N个事务后
    才 fsync 写入磁盘,这种如果机器宕机会丢失N个事务的binlog。
    发生以下任何事件时, binlog日志文件会重新生成:
    • 服务器启动或重新启动
    • 服务器刷新日志,执行命令flush logs
    • 日志文件大小达到 max_binlog_size 值,默认值为 1GB

如果要恢复大量数据,比如程序员经常说的删库跑路的话题,假设我们把数据库所有数据都删除了要怎么恢复
了,如果数据库之前没有备份,所有的binlog日志都在的话,就从binlog第一个文件开始逐个恢复每个binlog文件里
的数据,这种一般不太可能,因为binlog日志比较大,早期的binlog文件会定期删除的,所以一般不可能用binlog文
件恢复整个数据库的。
一般我们推荐的是每天(在凌晨后)需要做一次全量数据库备份,那么恢复数据库可以用最近的一次全量备份再加上备
份时间点之后的binlog来恢复数据。
备份数据库一般可以用mysqldump 命令工具

mysqldump ‐u root 数据库名>备份文件名; #备份整个数据库
mysqldump ‐u root 数据库名 表名字>备份文件名; #备份整个表
mysql ‐u root test < 备份文件名 #恢复整个数据库,test为数据库名称,需要自己先建一个数据库test

为什么会有redo log和binlog两份日志呢?
因为最开始 MySQL 里并没有 InnoDB 引擎。MySQL 自带的引擎是 MyISAM,但是MyISAM 没有 crash-safe 的能
力,binlog 日志只能用于归档。而 InnoDB 是另一个公司以插件形式引入 MySQL 的,既然只依靠 binlog 是没有
crash-safe 能力的,所以InnoDB 使用另外一套日志系统——也就是 redo log 来实现 crash-safe 能力。
有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为crashsafe

7.2.6 undo log回滚日志

InnoDB对undo log文件的管理采用段的方式,也就是回滚段(rollback segment) 。每个回滚段记录了 1024 个
undo log segment ,每个事务只会使用一个undo log segment。

在MySQL5.5的时候,只有一个回滚段,那么最大同时支持的事务数量为1024个。在MySQL 5.6开始,InnoDB支持
最大 128个回滚段,故其支持同时在线的事务限制提高到了 128*1024 。

innodb_undo_directory:设置undo log文件所在的路径。该参数的默认值为"./",即innodb数据文件存储位置,目录
下ibdata1文件就是undo log存储的位置。
innodb_undo_logs: 设置undo log文件内部回滚段的个数,默认值为128。
innodb_undo_tablespaces: 设置undo log文件的数量,这样回滚段可以较为平均地分布在多个文件中。设置该参数
后,会在路径innodb_undo_directory看到undo为前缀的文件。

undo log日志什么时候删除
新增类型的,在事务提交之后就可以清除掉了。
修改类型的,事务提交之后不能立即清除掉,这些日志会用于mvcc。只有当没有事务用到该版本信息时才可以清
除。

为什么Mysql不能直接更新磁盘上的数据而且设置这么一套复杂的机制来执行SQL了?
因为来一个请求就直接对磁盘文件进行随机读写,然后更新磁盘文件里的数据性能可能相当差。
因为磁盘随机读写的性能是非常差的,所以直接更新磁盘文件是不能让数据库抗住很高并发的。
Mysql这套机制看起来复杂,但它可以保证每个更新请求都是更新内存BufferPool,然后顺序写日志文件,同时还能
保证各种异常情况下的数据一致性。
更新内存的性能是极高的,然后顺序写磁盘上的日志文件的性能也是非常高的,要远高于随机读写磁盘文件。
正是通过这套机制,才能让我们的MySQL数据库在较高配置的机器上每秒可以抗下几干甚至上万的读写请求。

7.2.7 错误日志

Mysql还有一个比较重要的日志是错误日志,它记录了数据库启动和停止,以及运行过程中发生任何严重错误时的相
关信息。当数据库出现任何故障导致无法正常使用时,建议首先查看此日志。
在MySQL数据库中,错误日志功能是默认开启的,而且无法被关闭。

# 查看错误日志存放位置
show variables like '%log_error%';

7.2.8 通用查询日志

通用查询日志记录用户的所有操作,包括启动和关闭MySQL服务、所有用户的连接开始时间和截止时间、发给
MySQL 数据库服务器的所有 SQL 指令等,如select、show等,无论SQL的语法正确还是错误、也无论SQL执行成功还是失败,MySQL都会将其记录下来。
通用查询日志用来还原操作时的具体场景,可以帮助我们准确定位一些疑难问题,比如重复支付等问题。
general_log:是否开启日志参数,默认为OFF,处于关闭状态,因为开启会消耗系统资源并且占用磁盘空间。一般
不建议开启,只在需要调试查询问题时开启。
general_log_file:通用查询日志记录的位置参数。

show variables like '%general_log%';
# 打开通用查询日志
SET GLOBAL general_log=on;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/908337.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WPF 字符竖向排列的排版格式(直排)表明控件

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

新建Vue3项目流程

新建Vue3项目流程​一、环境准备​​ 创建Vue3项目前,需确保系统安装以下工具:• ​​Node.js​​:建议使用LTS版本(≥18.3),可通过node -v命令检查是否安装成功;• ​​包管理工具​​:推荐使用npm(Node.js自…

G. Chimpanzini Bananini

View PostG. Chimpanzini BananiniG. Chimpanzini Bananini大致题意:有以下三种操作:循环右移数组,即 \([a_1, a_2, \ldots, a_n]\) 变成 \([a_n, a_1, a_2, \ldots, a_{n-1}]\)。 反转数组,即 \([a_1, a_2, \ldot…

深入解析:HSA35NV001美光固态闪存NQ482NQ470

深入解析:HSA35NV001美光固态闪存NQ482NQ470pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", &qu…

ERP和MES、WMS、CRM,到底怎么配合 - 智慧园区

最近和不少老板聊ERP的时候,有句话听得特别多:总部说上了ERP就够了 可仓库说还要WMS 生产说MES必不可少 销售又提CRM这些系统到底怎么配合? 这话一出,就把企业信息化的痛点揭示出来了—— 很多老板以为ERP能包打天…

YOLO实战应用 1YOLOv5 架构与模块

实战应用 YOLOv5 架构与模块 核心概念YOLOv5:YOLO 系列的工程化实现,结构更简洁,代码更易读。 配置文件解析:通过 .yaml/.cfg 文件逐层定义网络结构。 Focus 模块:将输入图像切片重组,降低空间分辨率的同时增加…

YOLO实战应用 2数据准备与增强

实战应用 2数据准备与增强 核心概念残差模块 (shortcut / cover block):通过卷积与捷径连接实现特征相加,保证深层网络训练稳定。 NMS(非极大值抑制):用于去除多余重叠框,提升检测结果的准确性。 Soft-NMS:对高…

Day18稀疏数组

二维数组中的大部分默认值都为零,导致记录了许多没有意义的数据,稀疏数组用坐标对应有效值的方式大大简化了原本繁杂的数组package com.cc.array;import java.util.Arrays;public class ArrayDemo8 {public static v…

底层

面向过程转变成面向对象的底层逻辑 本套课程有一定难度,讲得不好,请多多包涵!里面有很多我的个人见解(仅供参考!如有指导,请把邮件发送到该邮箱690141760@qq.com) 如果有人问面向对象四大特征是什么?我相信基本…

YOLO实战应用 3训练与优化策略

实战应用 3训练与优化策略 核心概念数据加载与缓存:通过缓存机制提升训练效率,避免重复读取和处理标签。 Mosaic 数据增强:随机拼接四张图像,提升数据多样性与模型鲁棒性。 Batch 构建:一次迭代处理多个样本,并…

WPF 视图缩略图控件(支持缩放调节与拖拽定位)

实现 WPF 应用中画布的缩放控制与缩略图导航,支持滑块调节缩放比例、缩略图拖拽定位,实时同步主画布视图与缩略图视口位置。缩放控制:通过 Slider 值变化计算缩放比例,同步更新主画布 ScaleTransform,并调整 Scro…

实用指南:Dify关联Ollama

实用指南:Dify关联Ollama2025-09-20 12:21 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; f…

ik中文分词器使用

IK分词器介绍 在ElasticSearch中默认使用的分词器为Standard分词器,该分词器对中文不友好,对中文的处理方式是按单个汉字分词,无法识别中文里的词语、短语等语义单元。例如对于 "汉朝" 这个词,默认分词器…

动态水印也能去除?ProPainter一键视频抠图整合包下载

ProPainter是一个基于E2FGVI实现的AI视频编辑工具,它结合了增强的传播和Transformer机制,能够快速高效地进行视频修复和水印去除功能特点对象移除:智能地检测和移除视频中的动态物体,对于去除不需要的元素或错误…

SpringBoot整合RustFS:全方位优化文件上传性能

SpringBoot整合RustFS:全方位优化文件上传性能作为一名多年深耕分布式存储的架构师,我在多个企业级项目中成功实施SpringBoot与RustFS的集成。本文将分享一套​经过实战检验的性能优化方案,帮助你的文件上传速度提升…

javaScript(WebAPI) - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

windows使用es-client插件

下载插件并集成到浏览器 在各大浏览器应用商店搜索es-client,这里以edge浏览器作为演示,bing搜索“微软商店 插件 es-clint”,搜索结果第一条记录点击进去.点击右边的“获取”按钮,将插件添加到浏览器中。这里由于…

AI学习日记 - 实践

AI学习日记 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Co…

es中的端点

_doc端点 用于对单个****文档的crud操作(如创建、获取、更新、删除单个文档),常见用法如下向指定索引添加新文档: POST /索引名/_docES会自动生成唯一文档ID,例:POST /books/_doc → 向 books索引添加新文档。 根…

解码C语言宏

预处理概述 基本概念 预处理是C语言编译过程的第一步,所有以#开头的指令都由预处理器处理,这些指令不属于C语言语法本身。 预处理指令类型头文件包含:#include 宏定义:#define 宏取消:#undef 条件编译:#if, #ifd…