InnoDB 存储引擎体系结构 & update语句执行大致流程

可以看到,InnoDB 存储引擎主要分三大部分:

  • 内存结构
  • 后台线程
  • InnoDB 存储引擎文件

一、 内存结构

内存结构分为四部分:

  • Buffer Pool
  • Change Buffer(Insert buffer part of buffer pool)
  • Adaptive Hash Index
  • Log Buffer (Redo log buffer)

1. Buffer Pool

在启动时分配的内存区域,其大小由innodb_buffer_pool_size决定,缓存表与索引数据。对于专用的DB服务器,建议将60%~80%的物理内存分给此部分。

2. Change Buffer

缓存受DML操作影响的非唯一辅助索引(旧版本只能缓存insert,因此这部分之前也叫insert buffer)。如果其他读操作从磁盘中加载数据页到buffer pool时,这些页中正好也包含了change buffer中缓存的更改操作页,io_ibuf_thread线程会将change buffer中的记录真正合并到辅助索引中。

3. Adaptive Hash Index

用于管理缓冲池中的内部数据结构,并对缓冲池中的相关工作负载和内存操作组合进行自我调节。

4. Log Buffer

保存将要写入redo log的数据的内存区域,其大小由innodb_log_buffer_size决定,建议4~16M。innodb_flush_log_at_trx_commit参数决定何时将log buffer中内容写入日志,innodb_flush_log_at_timeout控制redolog刷新频率。

二、 后台线程

通过performance_schema.threads可以查询所有线程信息

select name,type,thread_id,processlist_id from performance_schema.threads where type='BACKGROUND';

image

可以看到MySQL后台线程一共有16种,其中最重要的有四大类——Master Thread、IO Thread、Purge Thread、Page Cleaner Thread。下面分别介绍名称及主要用途

类别 名称 用途
Master Thread srv_master_thread

InnoDB 存储引擎主线程。

5.6前:将buffer pool数据写入数据文件、执行检查点、undo页清理操作

5.6开始:工作大大减轻,主要通过4个循环来调用其他线程完成各项操作

IO Thread io_ibuf_thread 插入缓冲线程(ibuf指insert buffer)。负责change buffer的合并操作
io_read_thread 读IO操作线程,负责数据库的异步读取操作。数量由innodb_read_io_threads设置,默认为4
io_write_thread 写IO操作线程,负责数据库的异步写操作。数量由innodb_write_io_threads设置,默认为4
io_log_thread 日志线程,用于将redo log刷新到磁盘(lgwr)
Purge Thread srv_purge_thread undo清理线程,负责undo页清理操作。5.6之后新增,以减轻srv_master_thread负载
Page Cleaner Thread page_cleaner_thread 脏页清理线程,负责刷新脏页。5.6之后新增,以减轻srv_master_thread负载
Other srv_error_monitor_thread 错误监控线程,负责错误控制及处理
srv_lock_timeout_thread 锁线程,负责锁控制和死锁检测等
thread_timer_notifier 计时器过期通知线程,一般在超过max_execution_time后自动终止sql执行
main MySQL服务主线程(注意区别于InnoDB 存储引擎主线程),负责初始化、读取配置文件等功能
srv_monitor_thread InnoDB 监控打印进程,如果开启了InnoDB 监控器,会每隔5秒打印一次其采集的信息
srv_worker_thread InnoDB 工作线程。负责实际工作的线程,轮询从队列中取出任务(select,insert)等并执行
buf_dump_thread 缓冲池导入/出线程,负责缓冲池热点数据页导入/出
dict_stats_thread InnoDB 后台统计线程,负责InnoDB 表统计信息更新
signal_handler 信号处理线程,负责SIGTERM,SIGQUIT,SIGHUP信号处理的线程

三、 InnoDB 存储引擎文件

实际上只包含两大类数据 —— 表空间文件 和 redo log。

表空间可再细分为:

  • 系统表空间
  • 独立表空间
  • 常规表空间(5.7新增)
  • undo表空间
  • temp表空间(5.7新增)

 

1. 系统表空间

文件名为 .ibdata*,可被多个用户表共享。默认只会创建一个名为ibdata1的系统表空间文件,可以使用innodb_data_file_path参数指定系统表空间数量和大小。

系统表空间包含以下内容:

  • InnoDB数据字典(InnoDB相关对象元数据)
  • doublewrite buffer,防止“部分写”问题(pg则采用全页写机制),名字叫buffer但实际在磁盘上
  • undo segment(至少一个),用途同Oracle

2. 独立表空间(File-Per-Table Tablespaces)

设置innodb_file_per_table=1启用。若启用,则每个表都会生成一个.ibd文件用于存放自己的索引和数据;否则会统一存放在ibdata1系统表空间文件中。

3. 常规表空间(General Tablespaces)

5.7新功能,用户使用create tablespace语法创建的InnoDB共享表空间,文件名为tbs_name.ibd。

可使用  create table tb1 ... tablespace=xxx 或 alter table tb1 ... tablespace=xxx 将表添加到常规表空间中。

 

4. undo表空间

文件名为 undo* ,用途与Oracle相同,文件个数由innodb_undo_tablespaces控制。

InnoDB共支持128个undo段,其中32个undo段位于temp表空间,至少1个位于系统表空间,其余的位于undo表空间(最多95个)。

每个undo段有1023个事务槽位,并行事务场景中每个槽位对应一个事务。也就是说,对临时表操作的最大并行事务数为32*1023;对非临时表操作的最大并行事务数为96*1023。

5. temp表空间

存放非压缩的InnoDB临时表和相关对象,可通过innodb_temp_data_file_path参数定义文件名及初始大小,若未设置则默认创建一个初始12MB的名为ibtmp1的可自动扩展文件。

temp表空间在每次MySQL重启时会重新创建,如果无法创建,MySQL会启动失败。

temp表空间相关元数据存放在 information_schema.innodb_temp_table_info 表中。

6. redo log

用途同Oracle,默认会在磁盘中创建一组名为ib_logfile0和ib_logfile1的文件。

四、 update语句执行大致流程

假设正在执行以下语句

update test set idx=2 where id=10;
  • Server层进行权限验证、解析、语法验证、生成并选出较优的执行计划。
  • 到InnoDB引擎层,判断id=10的数据是否在buffer pool中。如果不在,需要从datafile中读入buffer pool,并对相关记录加独占锁;如果在,则略过读入的步骤。
  • 将idx修改前的值和对应主键、事务id信息写入undo表空间的回滚段中。
  • 更改缓冲池中对应页的数据,并将更新记录和新生成的LSN值写入log buffer中,更新后缓冲池中的该页就变为了脏页。
  • 提交事务时,先将log buffer中的更新数据刷新的redo log中,然后写binlog,对binlog进行提交(同步到磁盘),binlog同步后就将binlog文件名和位置也写入redo log。然后在redo log中写入一个commit标记,此时才真正完成了事务的提交。提交完后释放独占锁。
  • 如果开启了doublewrite buffer功能,刷新脏页时会先写一份到doublewrite buffer中,当doublewrite buffer中的数据落盘后,再从缓冲池把脏页刷新到数据文件。如果未开启,则直接由后台线程择机从缓冲池把脏页刷新到数据文件。

五、 MySQL 前台线程

前台线程也可通过performance_schema.threads可以查询

select name,type,thread_id,processlist_id from performance_schema.threads where type='FOREGROUND';

前台线程主要有5种,主要功能如下:

名称 用途
compress_gtid_table GTID压缩线程。用于压缩5.7新增的mysql.gtid_executed表中的GTID记录数
one_connection 用户连接线程,用于处理用户请求
slave_io IO线程,负责拉取主库binlog
slave_sql

SQL线程,单线程复制中负责apply主库binlog。

注意在多线程复制中,slave_sql作为协调器线程将binlog分发给slave_worker线程实际进行apply,而它负责对多个slave_worker进行协调

slave_worker 工作线程。多线程复制中,复制实际apply slave_sql线程分发的binlog

 

思维导图概要如下:

参考

《MySQL 性能优化金字塔法则》

《MySQL 技术内幕 InnoDB 存储引擎》

发布了295 篇原创文章 · 获赞 35 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/Hehuyi_In/article/details/100436554