InnoDB存储引擎

InnoDB存储引擎

InnoDB 引擎是MySQL数据库的一个重要的存储引擎、跟所有的二进制安装包里面、和其它的存储引擎相比、InnoDB引擎的优点是支持事务、以及参数完整性(有外键)等。MySQL5.5.5以后默认的存储引擎都是InnoDB引擎。

InnoDB的逻辑架构原理

InnoDB的逻辑架构有三个组成部分,分别是:在内存中的架构(In-Memory Structures)、操作系统缓存(Operating System Cache)和在硬盘上的架构(On-Disk Structures);这三个架构组成了一款高性能的InnoDB存储引擎。

内存中的架构(In-Memory Structures)

InnoDB在内存架构上主要分成四个部分,分别是:缓冲池(Buffer Pool)、写缓冲(Change Buffer)、日志缓冲(Log Buffer)以及自适应哈希索引(Adaptive Hash Index)。

  1. 缓冲池(Buffer Pool)

缓冲池是一块用于缓存被访问过的表和索引数据的内存区域,缓冲池允许在内存中处理一些被用户频繁访问的数据,在某一些专用的服务器上,甚至有可能使用80%的物理内存作为缓冲池。缓冲池的存在主要是为了通过降低磁盘IO的次数来提升数据的访问性能。

  1. 写缓冲(Change Buffer)

写缓冲是为了缓存缓冲池(Buffer Pool)中不存在的二级索引(Secondary Index)页的变更操作的一种特殊的内存数据结构。

​ 这些变更通常是一些Insert、Update、Delete等DML操作引发的,如果有一些其它的读操作将这些被变更的二级索引页加进了缓冲池(Buffer Pool),则这些变更会被马上合并至缓冲池中以保证用户可以读取到一致的数据。

  1. 日志缓冲(Log Buffer)

InnoDB将数据的每次写优化为了批量写,这便以降低磁盘IO的次数,为了防止一些数据尚未写入硬盘就断电了,需要记录日志;而日志缓冲就是用来缓存一些即将要被写入磁盘日志文件(log files)中的数据。

  1. 自适应哈希索引(Adaptive Hash Index)

在InnoDB中,用户是不可以直接去创建哈希索引的,这个自适应哈希索引是InnoDB为了加速查询性能,会根据实际需要来决定是否对于一些频繁需要被访问的索引页构建哈希索引,它会利用key的前缀来构建哈希索引。这样做可以提高查询性能,因为索引采用类似B+树的结构进行存储,B+树的单key查询时间复杂度为O(log2n),但是优化为哈希索引后,单key的查询时间复杂度就为O(1)了。

操作系统缓存(Operating System Cache)

操作系统为了提升性能而降低磁盘IO的次数,在InnoDB的缓存体系与磁盘文件之间,加了一层操作系统的缓存/页面缓存。用户态innodb存储引擎的进程向操作系统发起write系统调用时,在内核态完成页面缓存写入后即返回,如果想立即将页面缓存的内容立即刷入磁盘,innodb存储引擎需要发起fsync系统调用才可以。

硬盘上的架构(On-Disk Structures)

InnoDB在硬盘上总共分为六个部分,分别是表(Tables)、表空间(Tablespaces)、索引(Indexes)、双写缓冲(Doublewrite Buffer)、Redo日志和Undo段。

  1. 表(Tables)

    1. 如果已经指定了数据的默认存储引擎,那么创建表的时候,无需指定再指定存储引擎。
    2. 默认情况下,创建InnoDB表的时候innodb_file_per_table参数是开启的,它表明用户创建的表和索引,会被以单表单文件的形式放入到file-per-table表空间中。
    1. 如果禁用了该参数innodb_file_per_table,那么表及索引会被放入系统表空间(System Tablespaces)中。
    2. 如果创建表的时候,想要把表创建在通用表空间(General Tablespaces)中,那么需要用户使用CREATE TABLE … TABLESPACE语法来创建表结构。
  2. 表空间(Tablespaces)

    1. 系统表空间(System Tablespaces):系统表空间主要用于存储双写缓冲、写缓存以及用户创建的表和索引(当innodb_file_per_table被禁用的情况下)
    2. file-per-table表空间(file-per-tableTablespaces):存储用户创建的表和索引数据,默认情况下(innodb_file_per_table参数是启用的)
    1. 通用表空间(General Tablespaces):通用表空间允许用户存储一些自己想要放进通常表空间的表或数据,需要用户创建表的时候,自己指定采用通用表空间,上面讲表的时候已经介绍过。
    2. 回滚表空间(Undo Tablespaces):回滚表空间是为了存储回滚日志,通常回滚日志在表空间会以回滚段(Undo Segments)的形式存在。
    1. 临时表空间(Temporary Tablespaces):临时表空间用于存储用户创建的临时表,或者优化器内部自己创建的临时表。
  3. 索引(Indexes)

索引存在的目的主要是为了加速数据的读取速度,InnoDB采用BTree(实际为优化改进后的B+树索引)。主键索引也是聚集索引,二级索引都是非聚集索引。自适应哈希索引是InnoDB为了加速查询性能,它自己按需在内存中对加载进内存的BTree索引优化为哈希索引的一种手段。

  1. 双写缓冲(Doublewrite Buffer)

双写缓冲是一个在系统表空间System Tablespaces中存储区,在这个存储区中,在InnoDB将页面写入InnoDB数据文件中的适当位置之前,会先从缓冲池中刷新页面 。如果在页面写入过程中发生操作系统,存储子系统或mysqld进程崩溃,则InnoDB可以在崩溃恢复期间从双写缓冲中找到页面的原来的数据。

  1. Redo日志

redo即redo日志,是用于记录数据库中数据变化的日志,只要你修改了数据块那么就会记录redo信息。

你的每次操作都会先记录到redo日志中,当出现实例故障(像断电),导致数据未能更新到数据文件,则数据库重启时须redo,重新把数据更新到数据文件。

  1. Undo段

undo即undo段,是指数据库为了保持读一致性(原子性),存储历史数据在一个位置。 用于记录更改前的一份copy,用于回滚、撤销还原。

mysql> show global variables like '%undo%';
+--------------------------+------------+
| Variable_name            | Value      |
+--------------------------+------------+
| innodb_max_undo_log_size | 1073741824 |
| innodb_undo_directory    | ./         |
| innodb_undo_log_truncate | OFF        |
| innodb_undo_logs         | 128        |
| innodb_undo_tablespaces  | 0          |
+--------------------------+------------+
5 rows in set (0.00 sec)

mysql> show global variables like '%truncate%';
+--------------------------------------+-------+
| Variable_name                        | Value |
+--------------------------------------+-------+
| innodb_purge_rseg_truncate_frequency | 128   |
| innodb_undo_log_truncate             | OFF   |
+--------------------------------------+-------+
2 rows in set (0.00 sec)

innodb存储引擎执行流程

执行一条更新sql语句,存储引擎执行流程可以分为三大阶段,8个小步骤:

  1. 三大阶段

    1. 执行阶段:数据加载到内存,写undo log,更新内存中数据,写redo log buffer
    2. 事务提交阶段:redo log和binlog刷盘,commit标记写入redo log中
    1. 写入磁盘:后台io线程随机把内存中脏数据刷到磁盘上
  2. 八个小步骤

    1. 把该行数据从磁盘加载到buffer pool中,并对该行数据进行加锁
    2. 把旧数据写入undo log,以便修改出错情况下的回滚
    1. 在buffer pool中的数据更新,得到脏数据
    2. 把修改后的数据写入到redo log buffer当中
    1. 准备提交事务redo log刷入磁盘
    2. 把修改的操作记录准备写入binlog日志
    1. 把binlog的文件名和位置写入commit标记,commit标记写入redolog中(redo log中存放的修改后的数据与binlog中的修改操作对应上,双管齐下),事务才算提交成功;否则不会成功
    2. IO线程Buffer Pool中的脏数据刷入磁盘文件,完成最终修改

注:脏数据就是写入了内存中还没有来得及写入硬盘的数据就称之为脏数据。

InnoDB中进程

innodb存储引擎是多线程的模型,因此其在后台有多个不同的后台线程,负责处理不同工作任务。下面我们进行详细的讲解。

1、master thread

master thread是一个非常核心的后台线程,主要负责将缓冲池中的数据异步刷到磁盘,保障数据的一致性,其中包括脏页的刷新、合并插入缓冲(insert buffer) undo页的回收。

2、IO thread

在Innodb存储引擎中大量使用了AIO(Async IO)来处理写IO请求,这样可以极大提高了数据库的性能。而IO thread 的工作主要负责这些IO请求的回调(call back)处理。

innodb 1.0版本之前共有4个IO thread ,分别是write 、read 、insert buffer和log io thread。在linux平台下,iO thread 的数量不能进行调整,但是在window平台上可以通过参数innodb_file_io_thread来增大IO thread来增大IO thread ,从innodb 1.0.x版本开始,read thread 和write thread分别增大到了4个,并且不再使用innodb_file_io_threads参数,而是分别使用innodb_read_io_thread和innodb_write_io_threads参数进行设置。

mysql> show variables like '%io_thread%';
+-------------------------+-------+
| Variable_name           | Value |
+-------------------------+-------+
| innodb_read_io_threads  | 4     |
| innodb_write_io_threads | 4     |
+-------------------------+-------+
2 rows in set (0.00 sec)

查看IO thread进程状态

mysql> show engine innodb status\G
*************************** 1. row ***************************
  Type: InnoDB
  Name: 
Status: 
=====================================
2021-09-27 15:20:40 0x7fa18c620700 INNODB MONITOR OUTPUT
=====================================
--------
FILE I/O
--------
I/O thread 0 state: waiting for completed aio requests (insert buffer thread)
I/O thread 1 state: waiting for completed aio requests (log thread)
I/O thread 2 state: waiting for completed aio requests (read thread)
I/O thread 3 state: waiting for completed aio requests (read thread)
I/O thread 4 state: waiting for completed aio requests (read thread)
I/O thread 5 state: waiting for completed aio requests (read thread)
I/O thread 6 state: waiting for completed aio requests (write thread)
I/O thread 7 state: waiting for completed aio requests (write thread)
I/O thread 8 state: waiting for completed aio requests (write thread)
I/O thread 9 state: waiting for completed aio requests (write thread)
Pending normal aio reads: [0, 0, 0, 0] , aio writes: [0, 0, 0, 0] ,
 ibuf aio reads:, log i/o's:, sync i/o's:
Pending flushes (fsync) log: 0; buffer pool: 0
327 OS file reads, 158 OS file writes, 31 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 0.00 writes/s, 0.00 fsyncs/s

可以看到IO thread 0为insert buffer thread。io thread 1为log thread.之后就是根据参数innodb_read_io_thread及innodb_write_io_threads来设置的读写线程,并且读线程iD总是小于写线程。

3、Purge Thread

事务被提交后,其所使用的undolog可能不再需要,因为需要purge thread来回收已经使用并分配的undo页。在innodb1.1版本之前,purge操作仅在innodb存储引擎的master thread中完成,而从innodb1.1版本开始,purge操作可以独立到单独的线程中进行,以此来减轻master thread的工作,从而提供cpu的使用率以及提升存储引擎的性能,用户可以在配置文件中进行配置:

mysql> show variables like '%purge_thread%';
+----------------------+-------+
| Variable_name        | Value |
+----------------------+-------+
| innodb_purge_threads | 4     |
+----------------------+-------+
1 row in set (0.01 sec)

4、Page cleaner thread

Page cleaner thread作用是将之前版本中的脏页的刷新操作都放入到单独的线程中来完成,而其目的是为了减轻master thread 的工作及对于用户查询线程的阻塞,进一步提高innodb存储引擎的性能。

注:当内存数据页跟磁盘数据页内容不一致的时候,我们称这个内存页为“脏页”。

posted @ 2021-09-28 19:07  小丶凡  阅读(200)  评论(0编辑  收藏  举报
1