文章目录
- 逻辑存储结构
- 架构
- 内存结构
- Buffer Pool&Adaptive Hash Index
- Change Buffer
- Log Buffer
- 磁盘结构
逻辑存储结构
- 表空间(Tablespaces):InnoDB使用表空间来管理存储表和索引的数据文件。每个表空间包含一个或多个数据文件,这些文件实际上存储数据表和索引。
- 段(Segments):InnoDB将每个表空间划分为多个段,用于存储不同类型的数据。主要的段类型包括数据段、索引段、回滚段和系统段。数据段就是B+树的叶子节点, 索引段即为B+树的 非叶子节点。
- 区(Extent):每个段由一组区组成,每个区的大小通常为1MB。区是InnoDB中进行磁盘读写的最小单元,它包含了一组连续的数据页。
- 页(Page):区又由一组页组成,通常为16KB大小。页是InnoDB存储数据的最小单位,它可以包含表的行数据、索引数据以及其他管理信息。
- 行(Row):InnoDB使用”B+树”索引结构来组织数据。数据行存储在表的叶子页中,每一行代表一条记录。行数据包括所有列的值以及一些额外的管理信息。
- x_id:每次对某条记录进行改动时,都会把对应的事务id赋值给trx_id隐藏列。
- Roll_pointer:每次对某条引记录进行改动时,都会把旧的版本写入到undo日志中,然后这个隐藏列就相当于一个指针,可以通过它来找到该记录修改前的信息。
- 索引(Index):InnoDB使用聚集索引的方式来存储数据。每个InnoDB表都有一个主键索引,它决定了数据的物理存储顺序,并且作为其他非主键索引的查找入口。除了主键索引外,InnoDB还支持创建其他非主键索引,这些索引通常会占用额外的存储空间。
架构
MySQL5.5 版本开始,默认使用InnoDB存储引擎,它擅长事务处理,具有崩溃恢复特性,在日常开发
中使用非常广泛。下面是InnoDB架构图,左侧为内存结构,右侧为磁盘结构
内存结构
我们先来看看内存结构
主要分为这么四大块儿: Buffer Pool、Change Buffer、Adaptive Hash Index、Log Buffer。
Buffer Pool&Adaptive Hash Index
Buffer Pool 本质上是 InnoDB 向操作系统申请的一段连续的内存空间。InnoDB 的数据是按数据页为单位来读写,每个数据页的大小默认是 16KB。数据是存放在磁盘中,每次读写数据都需要进行磁盘 IO 将数据读入内存进行操作,效率会很低,所以提供了 Buffer Pool 来暂存这些数据页,缓存中的这些页又叫缓冲页。缓冲页的数据会以一定的频率刷新到磁盘中,减少了IO。
工作原理:
- 从数据库读取数据时,会首先从缓存中读取,如果缓存中没有,则从磁盘读取后放入 Buffer Pool
- 向数据库写入数据时,会写入缓存,缓存中修改的数据会定期刷新到磁盘,这一过程称为刷脏
Buffer Pool 以Page页为单位,每个缓冲页都有对应的控制信息,包括表空间编号、页号、偏移量、链表信息等,控制信息存放在占用的内存称为控制块,控制块与缓冲页是一一对应的,但并不是物理上相连的,都在缓冲池中。底层采用链表数据结构管理Page。
根据状态,将Page分为三种类型:
- free page:空闲page,未被使用。
- clean page:被使用page,数据没有被修改过。
- dirty page:脏页,被使用page,数据被修改过,也中数据与磁盘的数据产生了不一致。
MySQL 提供了缓冲页的快速查找方式:哈希表,使用表空间号和页号作为 Key,缓冲页控制块的地址作为 Value 创建一个哈希表,获取数据页时根据 Key 进行哈希寻址:
- 如果不存在对应的缓存页,就从 free 链表中选一个空闲缓冲页,把磁盘中的对应页加载到该位置
- 如果存在对应的缓存页,直接获取使用,提高查询数据的效率
Change Buffer
InnoDB 管理的 Buffer Pool 中有一块内存叫 Change Buffer 用来对增删改操作提供缓存,可以通过参数来动态设置,设置为 50 时表示 Change Buffer 的大小最多占用 Buffer Pool 的 50%
- 唯一索引的更新不能使用 Change Buffer,需要将数据页读入内存,判断没有冲突在写入
- 普通索引可以使用 Change Buffer,直接写入 Buffer 就结束,不用校验唯一性
Change Buffer 并不是数据页,只是对操作的缓存,所以需要将 Change Buffer 中的操作应用到旧数据页,得到新的数据页(脏页)的过程称为 Merge
- 触发时机:访问数据页时会触发 Merge、后台有定时线程进行 Merge、在数据库正常关闭(shutdown)的过程中也会触发
- 工作流程:首先从磁盘读入数据页到内存(因为 Buffer Pool 中不一定存在对应的数据页),从 Change Buffer 中找到对应的操作应用到数据页,得到新的数据页即为脏页,然后写入 redo log,等待刷脏即可
说明:Change Buffer 中的记录,在事务提交时也会写入 redo log,所以是可以保证不丢失的
业务场景:
- 对于写多读少的业务来说,页面在写完以后马上被访问到的概率比较小,此时 Change Buffer 的使用效果最好,常见的就是账单类、日志类的系统
- 一个业务的更新模式是写入后马上做查询,那么即使满足了条件,将更新先记录在 Change Buffer,但之后由于马上要访问这个数据页,会立即触发 Merge 过程,这样随机访问 IO 的次数不会减少,并且增加了 Change Buffer 的维护代价
补充:Change Buffer 的前身是 Insert Buffer,只能对 Insert 操作优化,后来增加了 Update/Delete 的支持,改为 Change Buffer。
下面是 InnoDB 存储引擎中修改数据的工作流程:
- 写操作:当有一个写操作需要修改某个非唯一索引时,例如插入、更新或删除操作,InnoDB 将首先将这个修改操作记录在 Change Buffer 中。
- Buffer Pool 中的修改:同时,InnoDB 会将被修改的数据页(包括索引页和数据页)加载到 Buffer Pool 中进行修改。在 Buffer Pool 中进行修改操作可以获得更快的访问速度和更低的 I/O 开销。
- 脏页标记:当数据页在 Buffer Pool 中被修改后,会被标记为 “dirty”,表示该页已被修改,需要在未来的某个时间点写回到磁盘。
- 脏页刷入:InnoDB 会异步进行脏页的刷入操作。这个过程称为 “flush”,通常由后台线程或异步刷新操作来完成。在刷入过程中,脏页的修改将被写回到磁盘上的对应数据文件中。
- 读操作:当其他查询或读取需要访问被修改的记录时,InnoDB 首先检查 Buffer Pool 中是否存在所需数据页。如果存在,数据将直接从 Buffer Pool 中获取。如果数据不在 Buffer Pool 中,则需要从磁盘读取对应的数据页到 Buffer Pool 中,然后再返回结果。
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(系统表空间): 系统表空间是数据库管理系统(DBMS)中的一个重要组件。它包含了系统表、用户表的元数据以及其他系统级数据。系统表空间通常以文件的形式存在,例如在MySQL中,系统表空间通常是由一个或多个.ibd或.frm文件组成。系统表空间对于数据库的正常运行至关重要。
File-Per-Table Tablespaces(独立表空间): 在一些数据库系统(如MySQL的InnoDB存储引擎)中,可以配置为每个表使用独立的表空间文件。这种配置方式称为”File-Per-Table”。每个表拥有自己的表空间文件,包括数据和索引。这种设计使得表的备份和恢复更加方便,并提供更好的性能和扩展性,同时减少数据碎片化的问题。
General Tablespaces(通用表空间): 通用表空间是MySQL 5.7版本中引入的特性。通用表空间允许将多个表存储在一个或多个共享表空间文件中。这种方式便于管理和维护数据库对象,可以更灵活地进行数据迁移和备份。
Undo Tablespaces(撤消表空间): 撤消表空间用于存储事务的撤消日志,也被称为回滚日志。在数据库中,事务修改数据时,撤消日志记录了对数据所做的修改,以便在回滚操作或崩溃恢复时撤销或恢复事务。
Temporary Tablespaces(临时表空间): 临时表空间用于存储临时表、排序和哈希操作等过程中的临时数据。这些临时数据在操作完成后会自动清除,临时表空间通常具有较高的性能要求。
Doublewrite Buffer Files(双写缓冲): 双写缓冲是InnoDB存储引擎中的一项机制,用于提高数据的写入可靠性。当InnoDB执行写入操作时,会先将数据写入双写缓冲区(一个内存缓冲区),然后再异步地将数据写入磁盘,以保证数据的一致性和可靠性。
Redo Log(重做日志): 重做日志是数据库管理系统中的一种日志机制,用于记录已经发生的事务操作。在数据库发生故障或崩溃时,通过重做日志可以将未提交的事务重新应用到数据库,恢复到故障发生前的状态。重做日志通常以文件的形式存在,是数据库持久性和可恢复性的重要保障。