逻辑存储结构

逻辑存储结构图

  1. 表空间

    表空间文件在Linux下存放在 /var/lib/mysql文件中的 xxx.ibd 文件就是表空间文件

    表空间文件用来存储,记录,索引等数据。

  2. 段分为,数据段(Leaf node segment)索引段(Non-leaf node segment)回滚段(Rollback segment),InnoDB是索引组织表,数据段就是B+树的叶子节点,索引段就是非叶子节点,段用来管理Extend(区)。

    一个段相当于一张表

  3. 区是表空间的单元结构,每个区大小为1M,默认情况下InnoDB存储引擎页大小为16k,一个区一共16个连续的页。

  4. 页,是InnoDB存储引擎磁盘管理的最小单元。

    每个区默认16KB,为了保证页的连续性,InnoDB存储引擎每次从磁盘申请4到5个区。

  5. 行指的是InnoDB存储的数据

    表结构中俩个隐藏字段

    Trx_id:最后一次操作事务的id

    Roll pointer:指针,指向增删改之前的数据,可以拿这个找到修改之前的数据。

架构

MySQL5.5版本后,默认使用InoDB存储引擎。

它擅长事务处理,具有崩溃恢复性特性!

下图为InnoDB架构图,左边为内存结构,右边为磁盘结构。

内存结构

Buffer Pool(缓冲池)

缓冲池是主内存的一个区域,里面可以缓存磁盘上经常操作的真实数据。

在执行增删改查操作的时候,先操作缓存池中的数据(如果没有,从磁盘加载并且缓存)

然后以一定频率刷新到磁盘,从而减少磁盘IO,加快处理速度

在缓存池中有一块一块的,这个是页。

缓存池以页为单位,底层采用链表数据结构管理Page。

根据状态将Page分为三类:

  1. free page :空闲页,未被使用的页。
  2. clean page :被使用的页,数据没有被修改过。
  3. dirty page :脏页,被使用的页,页中数据和磁盘中数据不一致。

Change Buffer(更改缓存区)

介绍

更改缓存区,主要针对非唯一的二级索引。

在执行DML语句时,如果这些数据页不在Buffer Poor中,不会直接操作磁盘,而是将数据变更在更改缓存区Change Buffer中

在未来数据被读取的时候,再将数据合并恢复到Buffer Pool中,再将合并后的数据刷新到磁盘中。

意义

和聚集索引不同,二级索引是非唯一的!

并且二级索引以相对随机的顺序插入。

同样的删除和更新可能会影响索引树中不相邻的二级索引页,如果每一次都操作磁盘,会造成大量磁盘IO。

有了ChangeBuffer后,我们可以在缓冲池中进行合并处理减少磁盘IO

Log Buffer(日志缓存区)

日志缓存区,用来保存要写入磁盘中的log日志数据(redo log 、undo log)。

默认大小16MB,日志缓存区的日志会定期刷新到磁盘中。如果需要更新、插入、或删除多行的事务,增加日志缓存区大小可以节约磁盘IO

在系统变量中设置即可

关键字:

innodb_log_buffer_size 缓存区大小

innodb_flush_log_at_trx_commit 日志刷新到磁盘的时机

1代表的是日志在每次事务提交时写入并刷新到磁盘

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

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

Adaaptive Hash index(自适应哈希索引)

自适应哈希索引,用于优化Buffer Pool数据的查询。

InnoDB存储引擎会监控表上各索引页的查询,如果观察到hash索引可以提高速度,就会建立hash索引。

这个叫自适应哈希索引

可以在系统变量中查询是否开启自适应哈希索引

关键字是 adaptive_hash_index

磁盘结构

System Tablespace(系统表空间)

系统表空间是change Buffer的存放区域。

关键字:innodb_data_file_path

系统表空间存放路径

File-Per-Table Tablespaces

存放每个表的独立表空间

默认是开启的-->开启后代表每一张表都会生成对应的表空间文件。

xxx.ibd结尾的文件都是表的表空间文件

查看变量 innodb_file_per_table看是开的还是关的

里面存放了表结构,表数据,索引

General Tablespaces(通用表空间)

通用表空间,需要手动通过

create tablespace 表空间名 add datafile '表空间对应的磁盘文件.ibd' engine=innodb;

创建通用表空间。

在创建表的时候可以指定该表空间

create table 表名(
字段....
)engine=存储引擎 tablespace 表空间名;

Undo Tablespaces(撤销表空间)

撤销表空间,MYSQL实例在初始化的时候会自动创建俩个默认的undo表空间(初始大小16M)用来存放undo log日志

默认叫 undo_001和undo_002

Temporary Tablespaces(临时表空间)

用来存储用户创建的临时表。

Doublewrite Buffer Files(双写缓冲区)

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

双写缓冲区文件:xxx.dblwr

Redo Log(重做日志)

用来实现事务的持久性。

该日志文件由俩个部分组成:重做日志缓冲区(redo log buffer)重做日志文件(redo log)

重做日志缓冲区:是在内存中

重做日志文件:是在磁盘在

事务提交后会把所有修改的信息存放在该日志中,用于刷新脏页到磁盘,发生错误时,进行数据恢复使用

以循环的方式写入重做文件,涉及到俩个文件:ib_logfile0和ib_logfile1

后台线程

作用:将Innodb缓冲池的数据在合适的时机刷新到磁盘文件中。

分为四类:

  1. Master Thread

    核心后台线程,负责调度其他线程。还负责将缓冲池中的数据异步刷新到磁盘中,保持数据的一致性。

    还包括,脏页的刷新合并插入缓冲undo页的回收

  2. IO Thread

    在InoDB存储引擎中大量使用了AIO来处理IO请求,这样可以极大提高数据库性能,IO Thread主要负责以下IO请求的回调

    线程类型 默认个数 责任
    Read thread 4 负责读操作
    write thread 4 负责写操作
    Log thread 1 负责将日志缓冲区刷新到磁盘
    Insert buffer thread 1 负责将写缓冲区内容刷新到磁盘

    关于AIO(异步IO)和IO(同步IO)

    同步就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。也就是必须一件一件事做,等前一件事做完了才能做下一件事。

    异步的概念和同步相对。当一个异步过程调用发出后,调用者不能立刻得到结果(在此期间,调用者可以去干一些别的事情)。实际处理这个调用的部件在完成后,通过状态、通知和回调。

  3. Purge Thread

    主要用于回收事务已经提交的undo log,在事务提交之后,undo log可能不需要了,就用这个来回收。

  4. Page Cleaner Thread

    协助Master Thread刷新脏页到磁盘的线程,他可以减轻Master Thread的工作压力,减少阻塞。

整个流程

在增删改查的时候,会操作内存结构区域,如果里面没有数据就从。磁盘结构中加载,然后进行操作。

最后在特定时间会自动从内存结构中刷新到磁盘中。在磁盘中进行持久化保存下来

事务原理

事务

事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有操作作为一个整体一起向系统提交撤销操作请求。

这些操作要么同时成功要么同时失败。

事务的四大性质

  1. 原子性

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

  2. 一致性

    事务完成时,必须使所有的数据保持一致性。

  3. 隔离性

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

  4. 持久性

    事务一旦提交或回滚,他对数据库的数据改变就是永久的。

事务的原理

事务的原子性,一致性,持久性都是由redo log和undo log实现的

事务的隔离性是由 锁机制和MVCC实现的。

redo log

重做日志,记录的是事务提交时数据页的物理修改用来实现事务的持久性

该日志文件由俩部分组成:

  1. 重做日志缓冲(redo log buffer)

    在内存中

  2. 重做日志文件(redo log file)

    在磁盘中

当事务提交后会把所有修改信息都存放到该日志文件中,用于在刷新脏页到磁盘中,发生错误时,进行数据的恢复。

大概流程:

  1. 客户端A对innoDB存储引擎的表进行增删改事务操作

  2. 先访问内存结构中的缓冲池,如果增删改数据在其中不存在,

    就会从磁盘中读取数据再刷新到缓冲池(这个数据必须是唯一索引,否则会先进入到更改缓冲区)

  3. 在缓冲池中变成脏页,并记录在redolog buffer中,后直接刷新到磁盘中

  4. 如果脏页在一段时间后刷新到磁盘中报错了,可以通过redo log进行恢复。

使用redo log直接刷新到磁盘结构的好处

事务一般是一组多条的增删改查操作,故事务提交的时候会随机的操作多条的记录。

这些记录会操作多条数据页,这样会产生大量的随机磁盘IO

而直接将redo log文件异步刷新到磁盘io中,由于它是日志文件,日志文件都是追加的,此时是顺序磁盘IO,这样会节约大量的磁盘IO

这种机制叫WAL(Write-Ahead Logging)(先写日志)

然后过一段时间脏页日志才会刷新到磁盘中。

故俩份日志是循环清理的

事务的redo log日志是为了解决脏页刷新到磁盘出错时进行数据的恢复使用的,用来保证数据的持久性

undo log

undo log日志是用来保证事务的原子性的。

undo log也叫回滚日志,用于记录数据被修改前的信息,作用为:提供回滚和MVCC

redo log记录的是物理日志!

undo log记录的是逻辑日志,可以认为当执行delete 一条记录时,undo log中会记录一条对应的insert记录,反之同理。

当执行rollback时,就可以从undo log中的逻辑记录读取到对应内容,从而进行回滚。

Undo log销毁

undo log在事务执行时产生,事务提交时,并不会马上删除undo log,因为这些日志可能还用于MVCC

Undo log存储

undo log采用,的方式进行管理和记录,存放在前面介绍的rollback segment回滚中,内部包含了1024个undo log segment

这个段是逻辑存储结构的段哦~

MVCC(多版本并发控制)(高频面试题)

MVCC的几个基本概念

当前读

我们读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁,

对于我们日常的操作,如:select...lock in share mode(共享锁),select...for update,update,insert,delete(排他锁)

都是一种当前读。

案例:

在RR的隔离级别下

  1. 事务A进行查询操作,事务B进行更新操作并提交事务
  2. 事务A使用当前读select...此时读取的是事务B更新之前的数据(原因是隔离级别)
  3. 事务A使用select...lock in share mode(当前读)此时读取的是事务B更新之后的数据。

快照读

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

  1. Read Committed隔离级别:每次select都生成一个快照读
  2. Repeatable Read隔离级别:开启事务后第一个select语句才是快照读的地方(后续查的就是这个快照数据)
  3. Serializable隔离级别:快照读会退化为当前读

MVCC介绍

全称Multi-Version Concurrency Control 多版本并发控制。

指的是维护一个数据的多个版本,使得读写操作没有冲突

快照读为MYSQL实现MVCC提供了一个非阻塞读功能,MVCC的具体实现,还需要依赖,数据库的三个隐藏字段

undo log日志readView

MVCC-实现原理

记录中的隐藏字段

当我们创建了表除了自己本身创建的字段,innoDB引擎会自动给我们创建三个字段

分别是:

  1. DB_TRX_ID
  2. DB_ROLL_PTR
  3. DB_ROW_ID
隐藏字段 含义
DB_TRX_ID 最近修改事务ID,记录插入这条记录或者最后一次修改该记录的ID(事务id)
DB_ROLL_PTR 回滚指针,指向这条记录的上一个版本,用于配合undo log指向上一个版本
DB_ROW_ID 隐藏主键,如果表结构没有指定主键,就会生成该隐藏字段

可以查看表空间文件内容来查看隐藏字段信息

事务id是自增的!

在MYSQL中提供了一个命令来查看表空间文件的记录信息

ibd2sdi xxx.ibd

undo log版本链

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

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

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

Undo log版本链

不同事务或相同事务对同一条记录进行修改,会导致该记录的undo log生成一个记录的版本链表,链表的头部是最新的旧记录,链表的尾部是最早的旧记录。

执行顺序:

从上到下代表执行顺序。在同一行代表同一时间执行。

ReadView(读视图)

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

ReadView中包含了四个核心字段

字段 含义
m_ids 当前活跃的事务id集合
min_trx_id 最小活跃的事务ID
max_trx_id 预分配事务ID,当前最大事务ID+1(因为事务ID是自增的)
creator_trx_id ReadView创建者的事务ID

版本链数据访问规则

trx_id 代表的是当前事务的id

用这个id和ReadView的四个核心字段进行比对

  1. trx_id == creator_trx_id 可以访问该版本 这个条件成立代表数据是当前这个事务更改的

  2. trx_id < min_trx_id 可以访问该版本 这个条件成立,说明数据已提交

  3. trx_id > max_trx_id 不可以访问该版本 这个条件成立,说明事务是在ReadView生成之后才开启的

  4. min_trx_id <= trx_id <= max_trx_id 如果trx_id不在m_ids中,就可以访问该版本

    这个条件成立,说明数据已经提交。

根据隔离级别的不同ReadView生成时机不同

  1. 在Read Committed隔离级别下

    在事务第一次执行快照读时都生成一个Read view

  2. 在Repeatable read隔离级别下

    在事务第一次执行快照读时生成,后续复用这个Read view

在RC隔离级别下,版本链访问原理分析

在事务第一次执行快照读时都生成一个Read view

第一个快照读,读取情况

这个快照读,根据规则,读取的是0x00002这个地址的数据,对应着事务2修改后的数据内容。

第二个快照读,读取情况

这个快照读,根据规则读取到的是,0x00003地址的数据内容,就是事务3修改后的数据。

在RR隔离级别下,版本链访问原理分析

在RR隔离级别下,只有事务在第一次执行快照读的时候生成ReadView,后续复用这个ReadView

具体的和RC规则一致,不重复讲解。

总结

隐藏字段+Undo log版本链+ReadView组成MVCC

MVCC+锁构成事务的隔离机制

事务的一致性由Redo log和undo log共同保证

MYSQL-->InnoDB引擎底层原理的更多相关文章

  1. 巧用MySQL InnoDB引擎锁机制解决死锁问题(转)

    该文会通过一个实际例子中的死锁问题的解决过程,进一步解释innodb的行锁机制 最近,在项目开发过程中,碰到了数据库死锁问题,在解决问题的过程中,笔者对MySQL InnoDB引擎锁机制的理解逐步加深 ...

  2. Mysql InnoDB引擎下 事务的隔离级别

    mysql InnoDB 引擎下事物学习 建表user CREATE TABLE `user` ( `uid` bigint(20) unsigned NOT NULL AUTO_INCREMENT, ...

  3. MySQL+InnoDB semi-consitent read原理及实现分析(转)

    add by zhj: 主要讲的是在MySQL在Repeatable Read和Read Committed级别下,加锁时的不同,在Read Committed隔离级别下,只对where 中满足条件的 ...

  4. 【原创】MySQL(Innodb)索引的原理

    引言 回想四年前,我在学习mysql的索引这块的时候,老师在讲索引的时候,是像下面这么说的 索引就像一本书的目录.而当用户通过索引查找数据时,就好比用户通过目录查询某章节的某个知识点.这样就帮助用户有 ...

  5. MySQL(Innodb)索引的原理

    引言 回想四年前,我在学习mysql的索引这块的时候,老师在讲索引的时候,是像下面这么说的 索引就像一本书的目录.而当用户通过索引查找数据时,就好比用户通过目录查询某章节的某个知识点.这样就帮助用户有 ...

  6. mysql学习笔记-底层原理详解

    前言 我相信每一个程序员都避免不了和数据库打交道,其中Mysql以其轻量.开源成为当下最流行的关系型数据库.Mysql5.0以前以MyISAM作为默认存储引擎,在5.5版本以后,以InnoDB作为默认 ...

  7. mysql innodb 引擎

    innodb 引擎 一.概述 InnoDB 是一个用的比较广泛的存储引擎,因为它支持事物和外键,还有不错的效率;我们先看看官方教程怎么说; 我们先读一下, 对于上面的文档, 对一个InnoDB的表首先 ...

  8. MySQL innodb引擎下根据.frm和.ibd文件恢复表结构和数据

    记录通过.frm和.ibd文件恢复数据到本地 .frm文件:保存了每个表的元数据,包括表结构的定义等: .ibd文件:InnoDB引擎开启了独立表空间(my.ini中配置innodb_file_per ...

  9. [MySQL]InnoDB引擎的行锁和表锁

    1.行锁和表锁 在mysql 的 InnoDB引擎支持行锁,与Oracle不同,mysql的行锁是通过索引加载的,即是行锁是加在索引响应的行上的,要是对应的SQL语句没有走索引,则会全表扫描, 行锁则 ...

随机推荐

  1. 后端统一处理返回前端日期LocalDateTime格式化去T,Long返回前端损失精度问题

    一.前言 我们在实际开发中肯定会遇到后端的时间传到前端是这个样子的:2022-08-02T15:43:50 这个时候前后端就开始踢皮球了,!! 后端说:前端来做就可! 前端说:后端来做就可! 作为一名 ...

  2. GreatSQL重磅特性,InnoDB并行并行查询优化测试

    欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 1 ...

  3. Docker Compose之容器编排开发初探

    1.前言 Docker Compose 是 Docker 官方编排(Orchestration)项目之一,负责快速在集群中部署分布式应用. Compose 是一个用于定义和运行多个 Docker 应用 ...

  4. [WPF]WPF设置单实例启动

    WPF设置单实例启动 使用Mutex设置单实例启动 using System; using System.Threading; using System.Windows; namespace Test ...

  5. Codeforces 1503C Travelling Salesman Problem(Dynamic Programming)

    题意 大家都是优秀生,这点英文还是看得懂的:点此看题 题解 由于旅行路线成一个环,所以从哪里出发不重要,我们把景点按照 a i a_i ai​ 排序,不妨就从左边最小的出发.基础的旅行费用 c i c ...

  6. C#基础_理解类

    构造函数主要是用来创建对象时为对象赋初值来初始化对象.总与new运算符一起使用在创建对象的语句中 .A a=new A(); 构造函数具有和类一样的名称:但它是一个函数具有函数的所有特性,同一个类里面 ...

  7. pod资源的健康检查-liveness探针的exec使用

    使用探针的方式对pod资源健康检查 探针的种类 livenessProbe:健康状态检查,周期性检查服务是否存活,检查结果失败,将重启容器 readinessProbe:可用性检查,周期性检查服务是否 ...

  8. SpringMVC 01: SpringMVC + 第一个SpringMVC项目

    SpringMVC SpringMVC概述: 是基于MVC开发模式的框架,用来优化控制器 是Spring家族的一员,也具备IOC和AOP 什么是MVC: 它是一种开发模式,是模型视图控制器的简称,所有 ...

  9. OSI七层模型与TCP/IP协议

    作者:菘蓝 时间:2022/9/1 ================================================================================== ...

  10. zabbix_agentd断断续续端无法访问问题记录

    问题现象: zabbix监控上出现zabbix_agentd无法访问,但是实际上zabbix_agentd是存活状态 每隔一段时间就会出现这样的情况 问题原因 zabbix_agentd端任务较多,活 ...