我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Mysql InnoDB 的内存结构详情

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Mysql InnoDB 的内存结构详情

1 前言

我们都熟悉mysql数据库服务架构,也清楚 sql 的执行顺序,mysql的数据在磁盘和内存中的存储结构是采用B+树的数据结构,但是在InnoDB引擎中,数据在内存和磁盘中的展示形式以及怎么和mysql的服务架构建立联系,sql 查询和 InnoDB 引擎之前的联系,可能就不是不清楚了。

mysql 的逻辑架构图如下所示: 

2 InnoDB 存储引擎结构

InnoDB存储引擎的逻辑存储结构是什么呢,其实所有的数据都被逻辑地放在了一个空间中这个空间中的文件就是实际存在的物理文件,即表空间。默认情况下,一个数据库表占用一个表空间,表空间中存放该表对应的数据、索引、insert buffer bitmap undo信息、insert buffer 索引页、double write buffer 等是放在共享表空间中的。

# 默认一个数据库表单独占有一个表空间
show variables like '%innodb_file_per_table%'
innodb_file_per_table=ON
# 修改设置
SET GLOBAL innodb_file_per_table=OFF; 

2.1 InnoDB表存储引擎文件

 每个表空间由 段 segment 区 extent 页 page 组成。页是数据存储数据的基本单位,默认大小为 16kb。 区是由连续页组成的空间,默认大小为 1MB。多个区构成表的段。 InnoDB 逻辑存储结构 

在我们执行sql时,不论是查询还是修改,myql 总会把数据从磁盘读取内内存中,而且在读取数据时,不会单独加在一条数据,而是直接加载数据所在的数据页到内存中,而读取的方式有两种,现行预读方式和随机预读方式,默认采用线性预读方式。

InnoDB 引擎架构 :

2.2 InnoDB 预读机制

线性预读和随机预读:

线性预读是以 extent 为单位,而随机预读是以 extent 中的page 为单位,线性预读着眼于将下一个extent 数据读取到 buffer pool 中,而随机预读是将当前extent中剩余的page读到 buffer pool 中。 如果一个extent 区中被顺序读取得page数量超过一定的数量( innodb_read_ahead_threshold),则直接加载 extent 中剩余的数据页。

2.3 InnoDB 特性

2.3.1 插入缓存

插入缓冲(Insert Buffer/Change Buffer)为了提升插入性能,insert buffer 是 insert buffer 的增强版,insert buffer 只对插入有效,而change buffer对 insert/update/delete 都有效。插入缓存只对非唯一索引和辅助索引有效,对每一次的插入不是写到索引页中,而是先判断插入的非聚集索引页是否在缓存中,如果在则直接插入,不存在则插入到 insert buffer 中,按照一定的频率进行合并操作,写回到磁盘。这样将多个插入操作合并进一个操作中,目的是为了减少随机IO带来的性能损耗。

2.3.2 二次写 (double write)

插入缓存给 InnoDB 存储引擎带来了性能上的提升,而 double write 则是保障 InnoDB 存储引擎操作数据页的可靠性。double write 分为两部分组成,一部分在内存中的 double write buffer, 大小为 2MB,另一部分是物理磁盘上共享表空间中连续的128个数据页,即2个区大小(同样是2MB)。在对缓冲池的脏页进行刷新时,并不是直接写磁盘,而是通过 memcpy 函数将脏页复制到内存中的 doublewrite buffer,之后通过doublewrite buffer 在分两次,每次1MB 顺序地写入共享表空间的物理磁盘上,然后马上调用 fsync 将数据同步至磁盘。由于doublewrite 是连续的空间,这样的顺序写IO开销不大。在doublewrite页写完后,再次离散写入各个表空间。如果操作系统在将数据页写入磁盘发生崩溃,那么在恢复的过程中,InnoDB 引擎会从共享表空间中的doublewrite找到该页的一个副本,将其复制到表空间文件,再应用重做日志。

2.3.3 自适应hash索引

hash是一种等值查询,InnoDB 存储引擎会监控对表上各个索引页的查询,如果观察到建立hash索引会带来速度提升,则建立相应的索引,因此称为自适应哈希索引(Adaptive Hash Index,AHI)。AHI是通过缓冲池中的B+树页构造而来,建立速度比较快,而且不需要对整张表建立哈希索引,只是建立热点页的索引。AHI默认是开启的状态。

2.3.4 异步IO

为了提高磁盘的操作性能, 当前的数据库系统一般采用异步IO(Asynchronous IO,AIO)的方式来处理磁盘操作,InnoDB 存储引擎也是如此,AIO的优势在于减少SQL查询需要的时间,另外也可以进行IO Merge 操作,就是将多个IO合并为1个IO,这样就可以提高IOPS的性能。

# 开启本地 AIO
show valiables like 'innodb_use_native_aio';

2.3.5 刷新邻接页

InnoDB 存储引擎提供了 Flush Neighbor Page(刷新邻接页)的特性,当刷新一个脏页时,InnoDB 存储引擎会检测该区内是否存在其它脏页,如果存在,则一并进行刷新,这样做得好处显而易见,可以将多个操作合并成一个操作,对于机械硬盘有着明显的优势,但对于固定硬盘,本事就有较高的IOPS,是否开启需要根据情况而定,

参数设置如下:

show varables like 'innodb_flush_neighbors'

3 sql 执行的逻辑

3.1 sql 执行

mysql写文件有2块缓存。一块是自己定义在内存的log buffer, 另一个是磁盘映射到内存的os cache。 mysql可以 调用 flush 主动将log buffer 刷新到磁盘内存映射,也可以调用 fsync 强制操作系同步磁盘映射文件到磁盘。默认情况下innodb_flush_log_at_trx_commit和sync_binlog 配置都为1。

不仅InnoDB引擎中有 buffer 的概念,这个是在用户空间中,而且在内核空间中也有 OS buffer的概念 

 还可以同时调用 flush + fsync, 将缓存直接落盘。
innodb_flush_log_at_trx_commit = 0就是每秒调用 flush + fsync ,定时器自己维护。
innodb_flush_log_at_trx_commit = 1就是实时调用 flush + fsync 没法批处理,性能很低。
innodb_flush_log_at_trx_commit = 2就是实时flush ,定时 fsync 交给OS维护定时器。
sync_binlog 配置
等于0:表示每次提交事务只write不fsync
等于1:表示每次提交事务都执行fsync
等于n:表示事务在write后,会累积N个事务后才fsync。

show variables like 'sync_binlog';
show variables like 'innodb_flush_log_at_trx_commit';
# 查看 mysql 正在执行的进程 
show processlist

InnoDB引擎BufferPool、LogBuffer、OS Buffer、Log files 之间的关系。 

mysql 在执行增删改sql时,InnoDB 引擎的执行步骤如下:

  • 1 执行器拿到需要执行的sql,需要根据更新条件从磁盘中加载需要修改的数据到内存中,也就是存放在 buffer pool 中。
  • 2 在修改对应的数据之前,需要将其数据进行备份,也就是将数据放进 undo log 中,方便在事务回滚时进行操作。
  • 3 直接在内存中按照sql语句修改对应的值。
  • 4 修改完后将按照修改后的数据写 redo log buffer。
  • 5 将 redo log 的内容进行写盘操作,这一步的操作参见 innodb_flush_at_trx_commit 的配置,一般是先写入系统的缓存中,然后由操作系统DMA异步操作写入系统文件中。 flush 操作只是把系统内存中的数据写入操作系统的缓冲中,数据读写一般是由内核线程完成的,这一步是数据从用户线程转变成内核线程进行操作,在读写文件时,在磁盘文件和内存之间会有多级缓存,用于提高数据交换效率,这里的 os cache 起到的就是这个作用。
  • 6 在写完redo log 后,然后进行 bin log 写入操作。
  • 7 和 redo log 的操作类似,也是先写入 os cache 再有操作系统刷到磁盘文件中。sync_log 的配置如图所示。一般情况下,数据库innodb_flush_at_trx_commit 和 sync_log 配置都为 1。
  • 8 在 redo log 和 bin log 写完后,就可以进行事务提交。在数据进行写盘操作时, InnoDB 采用两次写的方式进行写数据。

先写redo log 再写 bin log的原因: 由于mysql 是通过 bin log 进行复制传输的,如果先提交了 redo log,还没有写bin log时出现了宕机,mysql 实例恢复时根据 redo log进行恢复,就会造成 从库和主库之间的数据不一致。

二进制日志文件的记录格式为 statement、row 和 mixed,statement 模式就是直接执行sql,如果其中有函数操作(比如数据库时间设置为 now() )那就会造成数据不准确。row 模式就是同步所有行的数据,如果全表操作修改状态,那这种模式就不合适了,因此在数据同步时需要根据情况采用 mixed 的混合模式。

3.2 FreeList、LRU List 和 Flush List

Free List 空闲列表:

记录所有未被占用的数据页,按照顺序将加载到内存的数据放入buffer pool 中,并删除对应 Free List 中的节点

LRU List LRU 数据访问列表:

将冷热数据块连接起来,根据 LRU 算法进行维护。如果加载进内存的数据一次性放入列表头部,再不确定这批数据的热度情况下,会造成一部分数据的淘汰,mysql InnoDB 的做法是将数据放置在靠后的位置,如果数据在1s内被访问了,才能进入链表头部,即数据热区。

# 将新加载的数据放置在链表的位置 默认为 37 即5/8处,
show variables like 'innodb_old_blocks_pct';
# 冷区数据间隔多久访问才放入链表的热端,默认为1000ms
show variables like 'innodb_old_blocks_time';

Flush List 刷新脏页列表:

记录内存中修改的数据页,使用双向链表进行连接,在方便的时候做落盘操作。

InnoDB 中的 redo log 大小是固定的,在MYSQL数据库Innodb 引擎mvcc锁实现原理 中提到过 redo log 是保证事务持久性的,其文件个数也是可以根据需要进行配置,通过循环写文件的方式来实现的,当 write pos 追赶上 checkpoint 后,这个时候就不能再继续执行新的命令,需要把check point 往前推进,也就是把redo log 里的内容持久化,腾出空间继续写日志。

数据操作:

redo log buffer 循环写入 :

这里先写日志再写磁盘的关键点也是一个技术,Write-Ahead Logging(WAL技术)。

关于 redo log 的配置可以参见如下命令执行查看。

show variables like '%innodb_log%'
------- 执行结果 ------
innodb_log_buffer_size	16777216
innodb_log_checksums	ON
innodb_log_compressed_pages	ON
innodb_log_file_size	50331648
innodb_log_files_in_group	2
innodb_log_group_home_dir	./
innodb_log_write_ahead_size	8192
innodb_log_buffer_size 为内存中 redo log buffer 的大小,16777216/1024/1024=16MB
innodb_log_file_size 为每个redo log 的大小,50331648/1024/1024=48MB
innodb_log_files_in_group 为 redo log 文件组中文件的个数,默认为2个 
查看数据库表状态
show table status like 'my_table';

到此这篇关于Mysql InnoDB 的内存结构详情的文章就介绍到这了,更多相关Mysql InnoDB 内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Mysql InnoDB 的内存结构详情

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

MySQL Innodb 存储结构 和 存储Null值 用法详解

背景:表空间:INNODB 所有数据都存在表空间当中(共享表空间),要是开启innodb_file_per_table,则每张表的数据会存到单独的一个表空间内(独享表空间)。 独享表空间包括:数据,索引,插入缓存,数据字典。共享表空间包括:
2022-05-11

MySQL学习笔记(一)InnoDB内存数据结构浅析

Innodb存储引擎是目前MySQL最主流的存储引擎,学习Innodb, 可以先从其最基础的数据结构开始。Innodb的数据结构主要包括内存数据结构(In-MemoryStructures),如buffer pool, change buffer, log b
MySQL学习笔记(一)InnoDB内存数据结构浅析
2019-05-07

MySQL的InnoDB与HBase的存储结构对比

MySQL的InnoDB和HBase是两种不同类型的数据库管理系统,它们在存储结构、数据模型、访问方式等方面有着本质的区别。以下是它们之间的主要对比:存储结构对比MySQL的InnoDB:InnoDB使用B+树作为其索引结构,这是一种自平
MySQL的InnoDB与HBase的存储结构对比
2024-10-19

详解MySQL InnoDB存储引擎的内存管理

存储引擎之内存管理 在InnoDB存储引擎中,数据库中的缓冲池是通过LRU(Latest Recent Used,最近最少使用)算法来进行管理的,即最频繁使用的页在LRU列表的最前段,而最少使用的页在LRU列表的尾端,当缓冲池不能存放新读取
2022-05-13

MySQL InnoDB架构的相关总结

目录引言1、Mysql数据库整体架构SQL接口解析器优化器执行器存储引擎2、InnoDB存储引擎架构内存缓冲池undo log日志文件redolog日志文件binlog日志文件InnoDB执行流程引言作为一个后端程序员,我们几乎每天都要和数
2022-05-28

MySQL中InnoDB索引数据结构(B+树)详解

mysql的innodb的索引的B+树逐步讲解 B树B+树B树和B+树的不同点聚集索引 VS 非聚集索引总结(面试题)1.为什么不使用二叉查找树?2.为什么不使用平衡二叉树?3.为什么不使用B树?4.为什么MySQL选择B+树做索引
2023-08-17

1. MySQL体系结构——InnoDB存储引擎表、页结构、行记录格式

本章将重点分析表的物理存储特征,即数据在表中是如何组织存放的。也就是说,表就是关于特定实体的数据集合,这也是关系型数据库模型的核心。4.1 索引组织表在 InnoDB存储引擎中,表都是按照主键顺序存放的,这样的存储方式的表称为索引组织表。如果创建表时没有显式的
1. MySQL体系结构——InnoDB存储引擎表、页结构、行记录格式
2016-03-15

详解JAVA中的内存结构与重载

详解JAVA中的内存结构与重载?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。一.对象在JVM的内存结构JAVA内存管理由JVM来管理。1)堆,所有new出来的对象(包括成员
2023-06-14

编程热搜

目录