InnoDB存储引擎架构


前言

Mysql中提供了多种存储引擎,其中使用最常用的就是InnoDB和MyISAM,因为MyISAM不支持事务,所以在Mysql8的时候被移除了,我们使用Mysql大多数情况下没有选择存储引擎而是使用了默认的InnoDB,本文简单介绍了InnoDB存储引擎。文章对官方文档进行了简单的摘要讲解,有对InnoDB感兴趣的可以直接看官方文档。
官方文档:https://dev.mysql.com/doc/refman/5.7/en/innodb-storage-engine.html

一、存储结构

在这里插入图片描述
上图是Mysql官方提供的InnoDB架构图,可以看到InnoDB主要分为内存架构和磁盘结构两部分。

内存结构

内存结构主要是针对的是数据及其操作,内存结构又分为Buffer Pool、Change Buffer、Adaptive Hash Index和Log Buffer四部分:

  • Buffer Pool: 缓冲池,正常情况下直接从磁盘进行IO读取数据的效率是非常慢的,所以在InnoDB中提供了数据缓冲池,数据缓冲池里面不直接存放数据而是存放的Page页,将数据存放在了Page页中,在缓冲池Page页是通过链表形式来存放的。
    Page页有三种状态:空闲状态、使用状态和被修改状态,被修改状态也叫脏页,正常情况下对数据进行修改操作的时候先修改的是Page里面的数据,然后再把数据刷到文件中。
  • Change Buffer: 写缓冲区,正常情况下修改数据是先修改的缓冲池中Page的数据,但是缓冲池肯定不是所有的数据,而修改数据没有对应的Page数据的时候并不会直接把数据加载到缓冲池中去,而是放在了写缓冲区中记录,等到数据被读取的时候再把数据合并到缓冲池中。
  • Adaptive Hash Index: 自适应Hash索引,InnoDB存储引擎会根据Page页的访问频率和模式建立对应的Hash索引,这个索引是根据查询情况自动建立的,所以称为自适应Hash索引。
  • Log Buffer: 日志缓冲区,主要用来保存写入磁盘的(Redo/Undo)日志文件,日志缓冲区会定期刷新到磁盘log文件中,这样不用每次日志都进行磁盘IO操作,提高效率。

磁盘结构

磁盘结构主要针对的是表和表空间,磁盘结构分为Tablespaces、InnoDB Data Dictionary、Doublewrite Buffer、Redo Log和Undo Logs。

  • Tablespaces: 表空间,对于表空间大家应该都不陌生,用来存储表结构和数据的。表空间又被分为系统表空间、独立表空间、通用表空间、临时表空间等多种类型。
  • InnoDB Data Dictionary: 数据字典,InnoDB数据字典由内部系统表组成,这些表包含用于查找表、索引和表字段等对象的元数据。
  • Doublewrite Buffer: 双写缓冲区,我们知道数据修改先修改的Page页后又刷到磁盘的,在刷到磁盘前这些数据会先存放在双写缓存区中,双写缓存区是用来保障数据写入磁盘时候出现问题的备份。
  • Redo Logs: 重做日志,记录了所有缓冲池修改的数据,修改数据的时候先写日志,后修改的缓冲区,假设修改写入操作的时候数据库崩溃了或停电了,等下次启动通过重做日志来保持数据的正确性。
  • Undo Logs: 撤销日志,撤销日志是事务开始之前保存的数据备份,主要用来事务的回滚操作还原原来的数据。

二、线程模型

InnoDB中主要有Master Thread、IO Thread、Purge Thread和Page Cleaner Thread四种类型的线程来做数据处理。

  • Master Thread: 这是InnoDB中的主线程,主要负责其他线程的调度。
  • IO Thread: 这是InnoDB中用来做读写操作的线程,使用的AIO的方式有利于提高数据库性能。
  • Purge Thread: 这是用来回收undoLog的,undoLog是为了事务回滚使用的,当事务提交之后之前保存的undoLog就没用了需要回收。
  • Page Cleaner Thread: 这是同步Page页数据到磁盘的线程,修改数据后先修改Page页中的数据,后面通过这个线程来把数据同步刷新到磁盘。

三、数据文件

通过show variables like ‘%datadir%’ 命令可以查询Mysql中的数据文件存放在了哪里
在这里插入图片描述
进入到提示的文件夹查看一下存放的文件信息
在这里插入图片描述
其中这个mysql.ibd文件就是Mysql中存储数据的文件,当数据库出现问题后也可以通过这个文件来恢复数据。
在这里插入图片描述
这是官网给出的InnoDB数据文件的结构。可以看到是Tablespace(表空间) -> Segment(段) -> Extent(区) -> Page(页) -> Row(行)这样层层包含的关系的,Row就是我们最终看到的数据库中一行一行的数据。
在这里插入图片描述
Page页的大小默认是16k,可以通过show variables like ‘%innodb_page_size%’ 命令查看
在这里插入图片描述
尽管在Page中Row记录的大小是不缺定的,但是我们还是可以大体估算一个数的,如果能在Page中存放更多的Row,那么执行查询SQL语句将会变的更快。如何在Page中存放更多的Row,这与Row的行格式有一定的关系,行格式决定了行是如何物理存储的,这反过来又会影响查询和DML操作的性能。

InnoDB中Row的行格式分为REDUNDANT、COMPACT、 DYNAMIC和COMPRESSED四种。

  • REDUNDANT : 使用REDUNDANT行格式,表会将变长列值的前768字节存储在B树节点的索引记录中,其余的存储在溢出页上。对于大于等于786字节的固定长度字段InnoDB会转换为变长字段,以便能够在页外存储(如果某字段的信息过长,这时候会被单独分配空间叫作溢出页,该字段叫做页外列)。
  • COMPACT: 与REDUNDANT行格式相比,COMPACT行格式减少了约20%的行存储空间,但代价是增加了某些操作的CPU使用量。简单的说就是牺牲了部分CPU的性能来增加了磁盘IO的性能,如果CPU比较好而磁盘IO性能差点的服务器可以设置为该格式。
  • DYNAMIC: 使用DYNAMIC行格式,InnoDB会将表中比较长的可变长度的列值完全存储在页外,而索引记录只包含指向溢出页的20字节指针。DYNAMIC行格式支持大索引前缀,最多可以为3072字节。
  • COMPRESSED: COMPRESSED行格式提供与DYNAMIC行格式相同的存储特性和功能,但增加了对表和索引数据压缩的支持,如果存放长数据比较多的数据库可以考虑使用这种格式。

可以看到InnoDB中对于Row的处理比较注重对变长字段的处理,像一些VARCHAR、VARBINARY、TEXT等变长字段的长度是不固定的,占用的空间大小也是不固定的,如果内容太长非常占用空间。其中DYNAMIC格式相较于REDUNDANT格式的处理是只保留了B-Tree子节点指向,对于长的可变行完全行溢出,占用更小的空间意味着Page页可以存放更多的行,效率更快一点。Mysql之后默认使用的行格式为DYNAMIC。可以使用命令show variables like ‘innodb_%format’; 查看
在这里插入图片描述

阿里巴巴JAVA开发手册的处理

其实阿里巴巴JAVA开发手册对于很多建议等都很不错的,毕竟是大厂有经验的前辈们花心血总结的,没事可以多看一下研究一下为啥。
针对变长字段阿里巴巴Java开发手册中的建表规范就给出了明确的强制建议,首先看建表规范第七条,因为行格式对于可变长度的处理势必会影响效率,所以要求对于字符串长度相等的使用char类型来存储;再看第八条,如果一个常用的业务表上挂这个一个长字段而且还是存储的较长,会拖累业务表的执行效率,要求的是将长字段单独建立一个表去存放。

  1. 【强制】如果存储的字符串长度几乎相等,使用 char 定长字符串类型。
  2. 【强制】varchar 是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长度大于此值,定义字段类型为 text,独立出来一张表,用主键来对应,避免影响其它字段索引效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值