一、mysql应用场景及特点
MySQL是一个开源免费的关系型数据库管理系统(RDBMS),由瑞典MySQL AB公司开发,现属于Oracle旗下产品。
MySQL支持SQL,事务操作。架构简单,可扩展各类插件,读写性能都非常高,适用于联机事务处理系统。例如阿里会员,商品,导购,交易等核心系统中都大量运用了改造版本的MySQL数据库:xdb。
二、mysql体系架构

连接层
处理客户端和服务端TCP/IP链接请求。主要完成链接解析、授权认证、及相关的安全、权限校验。
服务层
主要完成核心服务功能,如SQL解析,SQL分析和优化,确定表查询顺序,是否利用索引,如果是select会完成缓存的查询,部分内置函数的执行,最后生成调用引擎层的执行操作指令。
引擎层
存储引擎负责MySQL中数据的存储和提取,服务层通过API和存储引擎进行通信。不同的存储引擎具有不同的存储结构,索引,可以根据自己的需要来选取合适的存储引擎。引擎层是mysql最重要的层,目前最常用的是InnoDB引擎,因此后面重点介绍存储引擎层。
存储层
数据存储层,主要是将数据(如: redolog、undolog、数据、索引、二进制日志、错误日志、查询日志、慢查询日志等)存储在文件系统之上,并完成与存储引擎的交互。
三、mysql常用存储引擎及特点
MySQL支持多种存储引擎,比如InnoDB,MyISAM,NDB等。不同的引擎有不同的特点:
InnoDB:在处理高并发写入、持久性和恢复能力方面表现出色。适用于电子商务、银行、金融等需要高并发写入和数据一致性的应用场景。 MySQL 5.5 之后默认使用的是InnoDB引擎。
MyISAM:具有较高的查询性能和数据插入性能,适用于读密集型应用,如新闻网站、博客等。但由于不支持事务和行级锁定,在高并发写操作的应用中表现不佳。MySQL 5.5 之前默认使用的是MyISAM引擎。
NDB:提供了高可用性、高可扩展性和强一致性,特别适合在线事务处理(OLTP)应用。它能够根据需要增加更多节点以处理更大的数据负载,并在内存中处理大部分数据以提升读写性能。
四、InnoDB引擎逻辑结构

Tablespace(表空间)
MySQL表空间是指存储表数据和索引的一个物理空间【对应一个或多个存储数据,索引的文件】,一个mysql可以对应多个表空间。
Segment(段)
段是InnoDB存储引擎中用于管理多个区(Extent)的逻辑结构。InnoDB存储引擎将数据划分为多个段,以便更有效地管理和访问数据。段不是物理上的连续存储区域,而是一个逻辑上的概念,由若干个零散的页面和一些完整的区组成。
在InnoDB中,段通常分为以下几种类型:
- 数据段(Leaf node segment):存放B+树的叶子节点,这些叶子节点包含了实际的数据行。
- 索引段(Non-leaf node segment):存放B+树的非叶子节点,这些节点包含了索引信息,用于加速数据的访问。
- 回滚段(Rollback segment):存放回滚数据,用于实现事务的回滚和多版本并发控制(MVCC)。
Extent(区)
Extent(区)是由多个连续的Page(页)组成的空间,它是InnoDB存储引擎中管理存储空间的一种单位。默认情况下,每个Extent包含64个连续的Page,而每个Page的大小默认为16KB。因此,一个Extent的大小通常是1MB。不过从InnoDB 1.0.x版本开始引入了压缩页,页大小可以通过参数KEY_BLOCK_SIZE设置为2K、4K或8K,因此每个区对应的页数也会相应变化。
Page(页)
Page是InnoDB磁盘管理的最小单位,与数据库相关的所有内容都存储在Page结构里。默认情况下每个Page的大小为16KB。这意味着InnoDB在磁盘和内存之间交互数据时,通常是以16KB为单位进行读写。数据页通常有以下几种类型:
- 数据页(B-Tree Node):用于存储表中的数据和索引信息。这是最常见的Page类型。
- Undo页(Undo Log Page):用于存储回滚日志信息,以支持事务的回滚操作。
- 系统页(System Page):存储InnoDB系统级别的信息,如Page的分配和回收情况等。
- 事务数据页(Transaction System Page):存储与事务相关的系统信息。
Row(行)
Page中的数据是按Row(行)进行存储的。
trx_id
代表事务 ID,用于标识最后一次对该行记录进行修改的事务。它占用 6 个字节的存储空间。trx_id
在 MVCC 中起到了至关重要的作用。
roll_pointer
是一个指针,用于指向该行记录的上一个版本在 undo 日志中的位置。它占用 7 个字节的存储空间。roll_pointer
在事务回滚和多版本读取中发挥着重要作用。
五、 InnoDB引擎物理结构

Buffer Pool
数据页缓冲区,负责缓存数据页和索引页,以加快数据的读写速度。在执行增删查改操作时,先操作缓冲池中的数据,若缓冲池中没有数据,则从磁盘加载并缓存,然后再以一定频率刷新到磁盘,从而减少磁盘IO,加快处理速度。
Buffer Pool中以Page页为单位,底层采用链表数据结构管理Page。Page分为三种类型:
- free page,空闲未被使用。
- clean page,被使用的page,但数据未被更改过。
- dirty page,被使用的page,数据被更改过,与磁盘数据产生了不一致。
Change Buffer
更改缓冲区,针对非唯一二级索引页,且数据不在Buffer Pool中的情况。
在执行数据删除更新时,可能会影响索引树中不相邻的二级索引,每次都操作磁盘都会造成大量磁盘IO,因此会先将变更数据存储在Change Buffer中,在未来数据读取时,再将数据合并恢复到Buffer Pool中,再将合并后的数据刷新到磁盘中。以减少数据更新时磁盘IO次数。
Adaptive Hash Index
自适应hash索引,用于优化对Buffer Pool中大量索引页数据的查询。
Log Buffer
日志缓冲区,当数据库执行 DML 操作(如 INSERT、UPDATE、DELETE)时,这些操作的变更信息会首先记录到 Log Buffer 中,而不是直接写入磁盘。
Log Buffer 中的日志信息包括事务的所有变更操作,这些操作被称为 redo 日志。日志信息在 Log Buffer 中缓存后,可以批量写入磁盘,进一步减少了磁盘 I/O 操作的开销。
Log Buffer 中的日志信息会在一定条件下(如事务提交、Log Buffer 满、后台检查点等)被刷新到磁盘上的 Redo Log 文件中。即使数据库崩溃或断电,存储在 Log Buffer 中的日志数据也能够通过 Redo Log 文件来恢复,从而保证数据的持久性。
System Tablespace(系统表空间)
- 存放位置:默认情况下,系统表空间的数据存储在名为ibdata1的文件中。
- 存储内容:包括InnoDB的数据字典、回滚日志(undo logs)、双写缓冲(doublewrite buffer)的存储区域(在MySQL 8.0.20之前),以及可能包含的表和索引数据(当表在系统表空间中创建时)。在MySQL 8.0中,InnoDB将元数据存储在MySQL数据字典中。
- 特点:系统表空间是InnoDB的默认表空间,也称为共享表空间。
File-Per-Table Tablespaces(独立表空间)
- 启用方式:通过设置innodb_file_per_table参数为ON来启用。
- 存储内容:每个表的数据和索引都会保存在一个单独的.ibd文件中。
- 特点:独立表空间使得每个表的数据更加独立,便于管理和备份。
General Tablespaces(通用表空间)
- 创建方式:通过CREATE TABLESPACE语法创建通用表空间,并在创建表时指定该表空间。
- 存储内容:可以存储多个表的数据和索引。
- 特点:提供了更加灵活的表空间管理方式。
Undo Tablespaces(撤销表空间)
- 存储内容:用于存储撤销日志(undo logs),这些日志用于支持事务的回滚操作。
- 特点:MySQL实例在初始化时会自动创建两个默认的撤销表空间文件(undo_001和undo_002),可以通过配置innodb_undo_directory属性来设置撤销表空间的位置。在MySQL 8.0.14及更高版本中,可以通过CREATE UNDO TABLESPACE语句来主动创建撤销表空间。
Temporary Tablespaces(临时表空间)
- 存储内容:用于存储用户创建的临时表和内部临时表的相关信息。
- 特点:InnoDB使用会话临时表空间和全局临时表空间来管理临时数据。
Redo Log(重做日志)
- 存储位置:重做日志文件通常以ib_logfile0、ib_logfile1等命名。
- 作用:记录了对数据库所做的所有更改,用于在数据库崩溃时进行恢复操作。
- 特点:重做日志是InnoDB存储引擎实现崩溃恢复功能的关键组件之一。
Undo Log(回滚日志)
- 存储位置:回滚日志默认存储在系统表空间中,也可以单独存储在撤销表空间中。
- 作用:支持事务的回滚操作,并用于实现多版本并发控制(MVCC)。
- 特点:回滚日志是InnoDB事务处理机制的重要组成部分。
Doublewrite Buffer(双写缓冲)
- 作用:提高数据的可靠性,防止部分写失效导致的数据丢失问题。
- 实现方式:双写缓冲由内存中的doublewrite buffer和物理磁盘上连续的128个页(两个区)组成。当缓冲池的脏页刷新时,会先将脏页拷贝到内存中的doublewrite buffer,然后再分两次写入到物理磁盘上的共享表空间中。完成doublewrite页的写入后,再将doublewrite buffer中的页写入各个表空间文件中。
六、 InnoDB引擎后台线程
Master Thread(主线程)
- 概述:Master Thread是InnoDB的核心线程,负责调度和管理其他线程的工作。
- 具体工作:包括定时刷脏页、回收undo log、写入redo log、合并写缓冲等。Master Thread会定期将重做日志缓冲中的内容刷新到磁盘,以确保事务的持久性。同时,它还会根据脏页的比例和系统的负载情况,动态调整刷新的频率和数量。此外,Master Thread还会定期合并插入缓冲,以提高写入性能。
- 内部循环:Master Thread内部包含多个循环,如主循环、后台循环、刷新循环和暂停循环。它会根据数据库运行的状态进行循环之间的切换。
IO Thread(IO线程)
- 概述:IO Thread专门负责处理IO操作,包括读线程、写线程、日志线程和插入缓冲线程等。每种线程负责处理不同类型的IO操作。
- 读线程:负责将数据从磁盘加载到Buffer Pool中。当数据页不在Buffer Pool中时,读线程会被唤醒,并异步读取数据到内存中。读线程的数量可以根据需要进行配置,多个读线程可以并行处理不同的读取请求,提高读取性能。
- 写线程:负责将Buffer Pool中的脏页(被修改但尚未写入磁盘的数据页)刷新到磁盘。写线程会根据脏页的比例和系统的负载情况,动态调整刷新的频率和数量。多个写线程可以并行处理不同的写请求,提高写入性能。
- 日志线程:负责将日志缓冲区中的内容刷新到磁盘的重做日志文件中。重做日志是InnoDB保证事务持久性的重要机制,日志线程确保了日志的写入顺序和一致性。日志线程通常只有一个,因为日志的写入是顺序的,不需要多个线程并行处理。
- 插入缓冲线程:负责将插入缓冲中的内容刷新到磁盘。插入缓冲是InnoDB用于优化非聚集索引插入操作的缓冲区,它可以将多个插入操作合并成一个,减少磁盘IO次数。插入缓冲线程会定期将缓冲中的数据写入到实际的索引页中,以提高写入性能。
Purge Thread(清除线程)
- 概述:当事务提交后,其使用的undo日志将不再需要。为了回收这些不再需要的undo页,InnoDB引入了Purge Thread。
- 功能:Purge Thread负责回收已经分配的undo页,并释放相应的空间供其他事务使用。它会定期扫描undo日志链表,将不再需要的undo页标记为可回收,并调用相应的写线程将其刷新到磁盘。
Page Cleaner Thread(页面清洁线程)
- 概述:Page Cleaner Thread是InnoDB中较新引入的线程类型,用于协助Master Thread处理脏页的刷新。
- 功能:当Master Thread忙于其他任务时,Page Cleaner Thread可以接管脏页的刷新工作,以减轻Master Thread的负担。它会定期扫描Buffer Pool中的脏页,并将其刷新到磁盘,以保持数据的一致性。