MySQL数据库进阶第六篇(InnoDB引擎架构,事务原理,MVCC)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
日志服务 SLS,月写入数据量 50GB 1个月
简介: MySQL数据库进阶第六篇(InnoDB引擎架构,事务原理,MVCC)

本文将带您遍览 InnoDB 存储引擎的内部机制,深入其逻辑存储结构和内存架构,解析页、段、区至行的层级,揭秘索引与数据是如何存放的。深入缓冲池的秘密,发现 InnoDB 如何以 Buffer Pool 为纽带,缓解物理硬盘与内存间的速度差异,保持高效。掌握更改缓冲区的智慧,理解非唯一二级索引背后的故事。嗅探自适应哈希索引和日志缓冲区,探寻其提升查询与事务写入的神奇之处。

文章还展现了 InnoDB 独特的磁盘结构布局,包含一应俱全的系统表空间、表级空间和特有的回滚机制,为数据的持久化与安全性搭建了坚实的基础。揭示了后台线程如何无声地协助数据在内存和磁盘间舞动,以及事务原理的严密逻辑,事务的 ACID 特性在 InnoDB 中如何实现。

最后,本文还深入探讨了 MVCC 的实现原理和细节,通过生动的快照读和 ReadView 机制,让并发控制如丝般顺滑,值得每位数据库爱好者细细品味。

一、InnoDB引擎逻辑储存结构

段,分为数据段、索引段、回滚段,InnoDB是索引组织表,数据段是B+树的非叶子结点,段用来管理多个区

区,表空间的单元结构,每个区大小为1M,默认情况下InnoDB存储引擎页大小为16K,即一个区公共有64个连续的页

页,是InnoDB存储引擎磁盘管理的最小单元,每个页的大小默认为16KB。为了保证页的连续性,每次InnoDB都会向磁盘申请4-5个区

行,InnoDB存储引擎数据是按照行进行存放的

记录中的每一列col1,col2,col3

两个隐藏列

Trx id,最后一次操作该行的事务ID

Roll pointer,每次对改行记录进行改动时,会把旧版本写入undo日志中,该值是指针,通过它可以找到之前没有改动的旧版本

二、架构——内存结构

InnoDB存储引擎基于磁盘文件存储,在物理硬盘和在内存中的速度相差很大,为了尽可能弥补这两者之间的I/O效率的差值,就需要把经常使用的数据加载到缓冲池中,避免每次访问都进行非常慢的且大部分都是随机的磁盘I/O。

在InnoDB的缓冲池中不仅缓存了索引页和数据页,还包含了undo页、插入缓存、自适应哈希索引以及 InnoDB的锁信息等等。

## Buffer Pool缓冲池

缓冲池 Buffer Pool,是主内存中的一个区域,里面可以缓存磁盘上经常操作的真实数据,在执行增 删改查操作时,先操作缓冲池中的数据(若缓冲池没有数据,则从磁盘加载并缓存),然后再以一定频率刷新到磁盘,从而减少磁盘IO,加快处理速度。

缓冲池以Page页为单位,底层采用链表数据结构管理Page。根据状态,将Page分为三种类型:

free page:空闲page,未被使用

clean page:被使用page,数据没有被修改过

dirty page:脏页,被使用page,数据被修改过,页中数据与磁盘的数据产生了不一致

## Change Buffer 更改缓冲区(针对于非唯一的二级索引页)

在执行DML(数据 增删改)语句时,如果这些数据Page 没有在Buffer Pool中,不会直接操作磁盘,而会将数据变更存在更改缓冲区 Change Buffer 中,在未来数据被读取时,再将数据合并恢复到Buffer Pool中,再将合并后的数据以一定频率刷新到磁盘中。

意义:与聚集索引不同,二级索引通常是非唯一的,并且以相对随机的顺序插入二级索引。同样,删除和更新 可能会影响索引树中不相邻的二级索引页,如果每一次都操作磁盘,会造成大量的磁盘IO。有了 ChangeBuffer之后,我们可以在缓冲池中进行合并处理,减少磁盘IO

## Adaptive Hash Index 自适应哈希索引

用于优化对Buffer Pool数据的查询。MySQL的innoDB引擎中虽然没有直接支持 hash索引,但是提供功能,即自适应hash索引。

hash索引对于等值匹配,一般性能高于B+树,因为hash索引一般只需要一次IO即可,而B+树可能需 要几次匹配,所以hash索引的效率要高,但hash索引又不适合做范围查询、模糊匹配等。

因此InnoDB存储引擎会监控对表上各索引页的查询,如果观察到在某条件下hash索引效率更高, 则建立hash索引,称为自适应hash索引。 自适应哈希索引无需人工干预,是系统根据情况自动完成。

## Log Buffer 日志缓冲区

Log Buffer:日志缓冲区,用来保存要写入到磁盘中的log日志数据(redo log 、undo log), 默认大小为 16MB,日志缓冲区的日志会定期刷新到磁盘中。如果需要更新、插入或删除许多行的事务,增加日志缓冲区的大小可以节省磁盘 I/O。

参数:innodb_log_buffer_size:缓冲区大小

参数:innodb_flush_log_at_trx_commit:日志刷新到磁盘时机,取值主要包含以下三个:

1日志在每次事务提交时写入并刷新到磁盘,默认值

0: 每秒将日志写入并刷新到磁盘一次

2: 日志在每次事务提交后写入,并每秒刷新到磁盘一次

三、架构——磁盘结构

磁盘结构

## System Tablespace 系统表空间

是更改缓冲区Change Buffer 的存储区域。如果表在系统表空间而不是每个表文件或通用表空间中创建的,它也可能包含表和索引数据。(在MySQL5.x版本中还包含InnoDB数据字典、undolog等)

## File-Per-Table Tablespaces

每张表的独立表空间,则每个表的文件表空间包含单个InnoDB表的数据和索引 ,并存储在文件系统上的单个数据文件中。 一个.ibd 对应一个表

## General Tablespaces 通用表空间

需要通过 CREATE TABLESPACE 语法创建通用表空间,在创建表时,可以指定该表空间

#创建表空间
CREATE TABLESPACE ts_name ADD DATAFILE 'file_name' ENGINE = engine_name;
#创建表时指定表空间
CREATE TABLE xxx ... TABLESPACE ts_name;
#-----------举例-----------
create tablespace ts_01 add datafile 'mydb01.ibd' engine = innodb;
创建表空间成功后,后续创建表时 可以指定把表创建至该表空间里

## Undo Tablespaces 撤销表空间

撤销表空间,MySQL实例在初始化时会自动创建两个默认的undo表空间(初始大小16M),用于存储 undo log日志,undo_001, undo_002

## Temporary Tablespaces 临时会话表空间

InnoDB 使用会话临时表空间和全局临时表空间。存储用户创建的临时表等数据。

## Doublewrite Buffer Files 双写缓冲区

双写缓冲区,innoDB引擎将数据页从Buffer Pool刷新到磁盘前,先将数据页写入双写缓冲区文件中,便于系统异常时恢复数据

## Redo Log 重做日志

用来实现事务的持久性。该日志文件由两部分组成:重做日志缓冲区(redo log buffer)(在内存结构的Log Buffer中)以及 重做日志文件(redo log),前者是在内存中,后者在磁盘中。

当事务提交之后会把所有修改信息存到该日志中,用于在刷新脏页到磁盘 发生错误时,进行数据恢复使用。以循环方式写入重做日志文件,涉及两个文件

四、架构——后台线程

内存中的数据和磁盘的数据 是怎么 写入和读取的呢?后台线程

## Master Thread(核心后台线程):

是MySQL的一个核心后台线程,负责管理和协调其他后台线程的工作,并将缓冲池中的数据异步刷新到磁盘中,保持数据的一致性;脏页的刷新、合并插入缓存、undo页的回收

## IO Thread(读写线程):

异步非阻塞IO 极大地提高数据库的性能,这些线程负责处理InnoDB存储引擎的IO请求,包括读取和写入磁盘上的数据。

## Purge Thread(清理线程):

Purge Thread负责回收已完成提交事务的undo log,将其释放以供后续事务使用。

## Page Cleaner Thread(页清理线程):

该线程负责在InnoDB存储引擎中执行脏页的刷新操作,将脏页写回磁盘,以确保数据的持久性和一致性。协助Master Thread。

五、事务原理

事务:一组操作的集合,要么全部成功,要么全部失败:

事务的四大特性:(ACID)原子性,一致性,隔离性,持久性

A:事务是不可分割的最小操作单元,要么全部成功,要么全部失败

C:事务完成时,必须使所有的数据都保持一致状态

I:数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行

D:事务一旦提交或回滚,它对数据库中的数据的改变就是永久的

持久性:redo log。重做日志

记录事务提交时,对数据页的物理修改,实现事务的持久性

包含两部分:重做日志缓冲(内存结构中的Log Buffer)与 磁盘的重做日志文件,提交后会把所有修改信息保存到该文件中,用于当刷新脏页到磁盘发生错误时 进行数据恢复使用

update/delete执行:

先看内存的BufferPool中有没有该页,如果没有该页则通过后台线程从磁盘中把页读到Buffer Pool

直接操作缓冲区中的数据,该页变成脏页

首先把数据页的物理变化记录在内存中的RodoLogBuffer,commit 事务提交的时候,redologBuffer会直接把数据页变化刷新到磁盘当中,即ib_logfile0,ib_logfile1中

在某个时机 该页以一定频率刷新到磁盘中进行持久化,若此时出错,则可以通过磁盘文件中的redo_log进行数据恢复

若脏页顺利写入磁盘,则redolog文件就不再需要,因此每过一段时间就清理一次redo log日志,是循环性的,不是永久的

日志文件都是追加的,是顺序磁盘I/O,效率比数据在磁盘的随机存取快速的多

WAL 先写日志 Write-Ahead Logging

原子性:undo log。回滚日志

用于记录被修改前的信息,作用包括两个:提供回滚 和 MVCC(多版本并发控制)

undo log 和 redo log 记录的物理日志不一样,它是逻辑日志。可以认为当delete一条记录时,undo log会记录一条对应的insert记录,反之亦然,当update一条记录时,它记录一条对应相反的 update记录(执行update之前 数据长的样子)。当执行rollback时,就可以从undo log中的逻辑记录读取到相应的内容并进行回滚

Undo log 销毁:undo log在事务执行时产生,事务提交时,并不会立即删除undo log,因为这些日志可能还用于MVCC

Undo log 存储:undo log采用段的方式进行管理和记录,存放在段中的rollback segment 回滚段中,内部包含1024个undo log segment

六、MVCC基本概念

当前读:读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。对于我们日常的操作,如:select … lock in share mode(共享锁),select … for update、update、insert、delete(排他锁)都是一种当前读。

客户端1使用select 语句,客户端2使用 update语句进行更新,因为当前隔离级别是可重复读,因此客户端1无法看到客户端2事务对数据的更改

当前读

快照读:简单的select(不加锁)就是快照读,快照读 读取的是记录数据的可见版本,有可能是历史数据, 不加锁,是非阻塞读

Read Committed 读已提交:每次select,都生成一个快照读

Repeatable Read 可重复高读:开启事务后第一个select语句才是快照读的地方。即第一次select查询产生快照读,后面的select查询直接使用前面的快照数据

Serializable 串行化:快照读会退化为当前读,每次读取都需要加锁

MVCC: Multi-Version Concurrency Control,多版本并发控制

维护一个数据的多个版本, 使得读写操作没有冲突,快照读 为MySQL实现MVCC提供了一个非阻塞读功能。MVCC的具体实现 依赖于数据库记录中的三个隐式字段、undo log日志、readView

七、MVCC实现原理

八、undo log日志 回滚日志,版本链

undo log日志 回滚日志

在insert、update、delete的时候产生的便于数据回滚的日志。

当insert的时候,产生的undo log日志只在回滚时需要,在事务提交后,可被立即删除

update、delete时,产生的undo log日志不仅在回滚时需要,在快照读时也需要,不会立即被删除

undo log 版本链

最终不同事务或相同事务对同一条记录进行修改,会导致该记录的undolog生成一条 记录版本链表。

链表的头部是最新的旧记录,链表尾部是最早的旧记录。

那么每次查询的时候,返回哪一个版本的记录呢?ReadView的作用

九、readView 读视图 决定查询读取 的记录

ReadView(读视图)是 快照读 SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务 (未提交的)id

不同的隔离级别,生成ReadView的时机不同:

READ COMMITTED :在事务中每一次执行快照读时生成ReadView

REPEATABLE READ:仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView

在RR隔离级别下,只是在事务中第一次快照读时生成ReadView,后续都是复用该 ReadView,那么既然ReadView都一样, ReadView的版本链匹配规则也一样, 那么最终快照读返 回的结果也是一样的

因此,MVCC的实现原理就是通过 InnoDB表的隐藏字段、UndoLog 版本链、ReadView来实现的。 而MVCC + 锁,则实现了事务的隔离性。 而一致性则是由redolog 与 undolog保证

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
2月前
|
存储 SQL 关系型数据库
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
|
3月前
|
人工智能 运维 关系型数据库
数据库运维:mysql 数据库迁移方法-mysqldump
本文介绍了MySQL数据库迁移的方法与技巧,重点探讨了数据量大小对迁移方式的影响。对于10GB以下的小型数据库,推荐使用mysqldump进行逻辑导出和source导入;10GB以上可考虑mydumper与myloader工具;100GB以上则建议物理迁移。文中还提供了统计数据库及表空间大小的SQL语句,并讲解了如何使用mysqldump导出存储过程、函数和数据结构。通过结合实际应用场景选择合适的工具与方法,可实现高效的数据迁移。
628 1
|
3月前
|
SQL 关系型数据库 MySQL
Go语言数据库编程:使用 `database/sql` 与 MySQL/PostgreSQL
Go语言通过`database/sql`标准库提供统一数据库操作接口,支持MySQL、PostgreSQL等多种数据库。本文介绍了驱动安装、连接数据库、基本增删改查操作、预处理语句、事务处理及错误管理等内容,涵盖实际开发中常用的技巧与注意事项,适合快速掌握Go语言数据库编程基础。
241 62
|
2月前
|
SQL 存储 关系型数据库
MySQL功能模块探秘:数据库世界的奇妙之旅
]带你轻松愉快地探索MySQL 8.4.5的核心功能模块,从SQL引擎到存储引擎,从复制机制到插件系统,让你在欢声笑语中掌握数据库的精髓!
|
2月前
|
SQL Oracle 关系型数据库
比较MySQL和Oracle数据库系统,特别是在进行分页查询的方法上的不同
两者的性能差异将取决于数据量大小、索引优化、查询设计以及具体版本的数据库服务器。考虑硬件资源、数据库设计和具体需求对于实现优化的分页查询至关重要。开发者和数据库管理员需要根据自身使用的具体数据库系统版本和环境,选择最合适的分页机制,并进行必要的性能调优来满足应用需求。
93 11
|
2月前
|
存储 监控 算法
园区导航系统技术架构实现与原理解构
本文聚焦园区导航场景中室内外定位精度不足、车辆调度路径规划低效、数据孤岛难以支撑决策等技术痛点,从架构设计到技术原理,对该系统从定位到数据中台进行技术拆解。
83 0
园区导航系统技术架构实现与原理解构
|
2月前
|
SQL 关系型数据库 MySQL
MySQL group by 底层原理详解。group by 执行 慢 原因深度分析。(图解+秒懂+史上最全)
MySQL group by 底层原理详解。group by 执行 慢 原因深度分析。(图解+秒懂+史上最全)
MySQL group by 底层原理详解。group by 执行 慢 原因深度分析。(图解+秒懂+史上最全)
|
2月前
|
SQL 关系型数据库 MySQL
【赵渝强老师】MySQL中的数据库对象
本教程详细介绍了MySQL数据库中的常见对象,包括表、索引、视图、事件、存储过程和存储函数的创建与管理。内容涵盖表的基本操作、索引的使用、视图简化查询、事件调度功能等,并通过具体示例演示相关SQL语句的使用方法。
|
3月前
|
存储 消息中间件 canal
zk基础—2.架构原理和使用场景
ZooKeeper(ZK)是一个分布式协调服务,广泛应用于分布式系统中。它提供了分布式锁、元数据管理、Master选举及分布式协调等功能,适用于如Kafka、HDFS、Canal等开源分布式系统。ZK集群采用主从架构,具有顺序一致性、高性能、高可用和高并发等特点。其核心机制包括ZAB协议(保证数据一致性)、Watcher监听回调机制(实现通知功能)、以及基于临时顺序节点的分布式锁实现。ZK适合小规模集群部署,主要用于读多写少的场景。

热门文章

最新文章

推荐镜像

更多