逻辑架构剖析
- MySQL是典型的C/S架构,服务端运行的程序是mysqld。
- 不论客户端和服务端进程采用哪种方式进行通信,最后实现的效果都是:客户端进程向服务端进程发送SQL语句,服务端进程处理之后将结果响应给客户端。
服务端处理过程如下所示

架构图

客户端连接器Connectors
- 指的是不同语言和MySQL的交互。MySQL在TCP之上定义了自己的应用层协议,我们可以使用MySQL的SDK和MySQL服务端进行交互。比如JDBC作为MySQL的Connector,本质上还是通过MySQL协议与MySQL进行交互
MySQL逻辑层
连接层
- 系统(客户端)访问 MySQL 服务器前,做的第一件事就是建立 TCP 连接。
- 经过三次握手建立连接成功后, MySQL 服务器对 TCP 传输过来的账号密码做身份认证、权限获取。
- 用户名或密码不对,会收到一个Access denied for user错误,客户端程序结束执行
- 用户名密码认证通过,会从权限表查出账号拥有的权限与连接关联,之后的权限判断逻辑,都将依赖于此时读到的权限
- MySQL服务器中有专门的TCP连接池限制连接数,采用长连接模式复用TCP连接
- 同时TCP接收到请求之后,必须分配一个线程用于处理与这个客户端的交互。每一个连接都从线程池中获取线程,避免了频繁创建和销毁线程带来的开销。
所以连接管理的职责就是负责认证、管理连接、获取权限信息

服务层
- 主要完成大多数核心服务功能。比如SQL接口,缓存的查询,SQL分析和优化以及部分内置函数的执行。所有跨存储引擎的功能也在这一层实现,比如过程、函数等。
- 在该层,服务器会解析查询并创建相应的内部解析树,并对其完成相应的优化:如确定查询表的顺序,是否利用索引等,最后生成相应的执行操作。
- 如果是SELECT语句,服务器还会查询内部缓存。如果缓存空间足够大,这样在解决大量读操作的环境中能够很好地提升系统的性能。
- SQL Interface(SQL接口):接收用户的SQL命令,并且返回用户需要查询的结果。MySQL支持DML(数据操作语言)、DDL(数据定义语言)、存储过程、视图、触发器、自定义函数等多种SQL语言接口
- Parser(解析器):
- 在解析器中对 SQL 语句进行语法分析、语义分析。将SQL语句分解成数据结构,并将这个结构传递到后续步骤,以后SQL语句的传递和处理就是基于这个结构的。如果在分解构成中遇到错误,那么就说明这个SQL语句是不合理的。
- 在SQL命令传递到解析器的时候会被解析器验证和解析,并为其创建语法树,并根据数据字典丰富查询语法树,会验证该客户端是否具有执行该查询的权限 。创建好语法树后,MySQL还会对SQL查询进行语法上的优化,进行查询重写。
- Optimizer(查询优化器):
- SQL语句在语法解析之后、查询之前会使用查询优化器确定 SQL 语句的执行路径,生成一个执行计划 。
- 这个执行计划表明应该
**使用哪些索引**进行查询(全表检索还是使用索引检索),表之间的连接顺序如何,最后会按照执行计划中的步骤调用存储引擎提供的方法来真正的执行查询,并将查询结果返回给用户。 - 使用”选取-投影-连接“策略进行查询
SELECT id,name FROM student WHERE gender = '女';
这个SELECT查询先根据WHERE语句进行 选取 ,而不是将表全部查询出来以后再进行gender过
滤。
这个SELECT查询先根据id和name进行属性 投影 ,而不是将属性全部取出以后再进行过
滤,将这两个查询条件 连接 起来生成最终查询结果。
- Caches & Buffers(查询缓存组件)
- MySQL内部维持着一些Cache和Buffer,比如Query Cache用来缓存一条SELECT语句的执行结果,如果能够在其中找到对应的查询结果,那么就不必再进行查询解析、优化和执行的整个过程了,直接将结果反馈给客户端。
- 这个缓存机制是由一系列小缓存组成的。比如表缓存,记录缓存,key缓存,权限缓存等 。
- 这个查询缓存可以在 不同客户端之间共享 。
- 从MySQL 5.7.20开始,不推荐使用查询缓存,并在 MySQL 8.0中删除 (命中率太低)。
引擎层
- 插件式的存储引擎架构将查询处理和其他的系统任务以及数据的存储提取相分离。使得可以根据业务的需求和实际需要选择合适的存储引擎。
- 负责MySQL中数据的存储与提取,对物理服务器级别维护的底层数据执行操作。服务器通过API与存储引擎进行通信。不同的存储引擎具有的功能不同,这样我们可以根据自己的实际需要进行选取。
- MySQL8.0.26支持的存储引擎如下
show ENGINES;
存储层(文件系统)
- 所有的数据,数据库、表的定义,表的每一行的内容,索引,都是存在 文件系统 上,以 文件 的方式存在的,并完成与存储引擎的交互。当然有些存储引擎比如InnoDB,也支持不使用文件系统直接管理裸设备,但现代文件系统的实现使得这样做没有必要了。在文件系统之下,可以使用本地磁盘,可以使用DAS、NAS、SAN等各种存储系统。
SQL执行流程
流程图

SQL执行流程
- 查询缓存:Server 如果在查询缓存中发现了这条 SQL 语句,就会直接将结果返回给客户端;如果没有,就进入到解析器阶段。
- 需要说明的是,因为查询缓存往往效率不高,所以在 MySQL8.0 之后就抛弃了这个功能。
- 两个查询请求在任何字符上的不同(例如:空格、注释、大小写),都会导致缓存不会命中。因此 MySQL 的 查询缓存命中率不高 。
- 假如查询的SQL中有系统函数,比如
NOW(),第一次查询跟第二次查询结果一样,这便会导致错误 - 缓存失效的情况:MySQL的缓存系统会监测涉及到的每张表,只要该表的结构或者数据被修改,如对该表使用了 INSERT 、 UPDATE 、 DELETE 、 TRUNCATE TABLE 、 ALTER TABLE 、 DROP TABLE 或 DROP DATABASE 语句,那使用该表的所有高速缓存查询都将变为无效并从高速缓存中删除!对于 更新压力大的数据库 来说,查询缓存的命中率会非常低。
解析器:对SQL进行语法分析、语义分析。如果没有错误会生成一个语法树

优化器:在优化器中会确定 SQL 语句的执行路径,比如是根据全表检索 ,还是根据索引检索 等。
- 一条SQL语句可能有很多种执行方式,最后都返回相同的结果。优化器的作用就是找到其中最好的执行计划。
- 执行器:在执行之前需要判断该用户是否 具备权限 。如果没有,就会返回权限错误。如果具备权限,就执行 SQL查询并返回结果。在 MySQL8.0 以下的版本,如果设置了查询缓存,这时会将查询结果进行缓存。
- 执行器通过调用存储引擎API调用存储引擎,存储引擎再调用文件系统来完成SQL语句的执行工作。
- 查询缓存:Server 如果在查询缓存中发现了这条 SQL 语句,就会直接将结果返回给客户端;如果没有,就进入到解析器阶段。
- 至此,MySQL的执行流程就是:
SQL语句->[查询缓存]->解析器->优化器->执行器
MySQL8.0中SQL执行原理
开启profiling,可以让MySQL收集SQL在执行时所使用的系统资源
查看开启状态:
show variables like 'profiling';注意这里查询的是全局的profiling状态

开启profiling:
set profiling=1;,0代表关闭,1代表开启这里设置的是当前Session的profiling状态,所以查询需要使用
select @@profiling;
执行SQL语句并查看profiling

除了耗时信息之外,还可以查看其他更加详细的信息
ALL是所有信息,也可单独查询cpu,io等信息

数据库缓冲池(buffer pool)
- InnoDB 存储引擎是以页为单位来管理存储空间的,我们进行的增删改查操作其实本质上都是在访问页面(包括读页面、写页面、创建新页面等操作)。
- 由于数据在磁盘上并不是连续存储的,每一块数据都被称为一个数据页,每个数据页大小为16kb。
- 磁盘 I/O 需要消耗的时间很多,而在内存中进行操作,效率则会高很多,为了能让数据表或者索引中的数据随时被我们所用,DBMS 会申请 占用内存来作为 数据缓冲池 ,在真正访问页面之前,需要把在磁盘上的页缓存到内存中的 Buffer Pool 之后才可以访问。
- 这样做的好处是可以让磁盘活动最小化,从而 减少与磁盘直接进行 I/O 的时间 。要知道,这种策略对提升 SQL 语句的查询性能来说至关重要。如果索引的数据在缓冲池里,那么访问的成本就会降低很多。
缓冲池&查询缓存
缓冲池
在 InnoDB 存储引擎中有一部分数据会放到内存中,缓冲池则占了这部分内存的大部分,它用来存储各种数据的缓存,如下图所示:

InnoDB在处理客户端的请求时,当需要访问某个页的数据时,会把完整的页的数据全部加载到内存中,也即我们如果只需要访问页中的某一个数据,也会先将整页数据加载进内存。在完成读写操作之后会将页缓存到缓冲池中,下次再访问就不需要从磁盘进行加载了。
缓存原则:
位置✖️频次,位置表示在内存还是磁盘,频次表示访问的页次数缓冲池的预读:局部性原理的体现。也即我们访问了某个页的数据,那么附近的数据大概率也会被访问到 ,因此采用预读机制加载进缓冲池,减少未来磁盘IO。
查询缓存
将查询的结果提前缓存起来,下次不需要再次执行就能获取到结果。MySQL8.0已经去除
缓冲池如何读取数据?
缓冲池管理器会尽量将经常使用的数据保存起来,在数据库进行页面读操作的时候,首先会判断该页面是否在缓冲池中,如果存在就直接读取,如果不存在,就会通过内存或磁盘将页面存放到缓冲池中再进行读取。

如果缓冲池中的数据更新了,会立即同步到磁盘中吗?
其实并不会,数据库会以一定频率将修改的数据刷新到磁盘中。而不是每次更新就立即将修改同步到磁盘中。这种机制叫做
checkpoint机制,这样可以提升数据库的整体性能。比如,当缓冲池不够用的时候,需要释放掉一些不常用的页,此时就会采用
checkpoint机制,将不常用的脏页回写到磁盘上,然后再从缓冲池中将这些页释放掉。这里的脏页(dirty page)指的是缓冲池中被修改过的页,与磁盘上的数据页不一致。查看、设置缓冲池的大小
- 对于MyISAM存储引擎,只缓存索引,不缓存数据,对应的键缓存参数是
key_buffer_size - 对于InnoDB存储引擎
可以通过
innodb_buffer_pool_size变量查看缓冲池的大小,默认大小是128M
修改缓冲池大小为256M:
set global innodb_buffer_pool_size = 268435456;
- 对于MyISAM存储引擎,只缓存索引,不缓存数据,对应的键缓存参数是
多个Buffer Pool实例
- 当线程去访问缓冲池中的数据的时候,需要进行加锁。这对于并发场景显然并不合适。所以可以将总的缓冲池划分为多个小的缓冲池。类似于分段锁。
- 查看缓冲池个数,默认为1:
SHOW VARIABLES LIKE 'innodb_buffer_pool_instances' - 比如缓冲池总大小为256M,分为2个缓冲池,那么每一个缓冲池大小为128M。
- InnoDB中,当缓冲池大小小于1G的时候,设置多个缓冲池是无效的。即使设置了,InnoDB也会修改成1。因为管理各个缓冲池也需要性能开销。
- 问题引申

当缓冲池中的数据更新了,磁盘中的数据还没有更新就宕机了,那么会不会导致数据不一致?
这就需要借助后面的RedoLog和UndoLog来实现数据的一致性
存储引擎
- 为了管理方便,人们把连接管理、查询缓存、语法解析、查询优化这些不涉及真实数据存储的功能划分为MySQL Server的功能。把真实存取数据的功能划分为存储引擎的功能。所以在MySQL Server完成了查询优化后,只需要按照生成的执行计划调用底层存储引擎提供的API,获取到数据返回给客户端即可
- 因为在关系数据库中数据的存储是以表的形式存储的,所以存储引擎也可以称为表类型(Table Type,即存储和操作此表的类型)。
- 功能就是接收上层传下来的指令,然后对表中的数据进行提取或写入操作。
- 在同一个MySQL服务器中,可以同时存在多个不同的存储引擎。比如表A的存储引擎是InnoDB,表B的存储引擎使用MyISAM,那么对A和B分别进行操作的时候,使用的存储引擎就分别是InnoDB和MyISAM。
查看、设置存储引擎
查看MySQL提供的存储引擎
SHOW ENGINES;同时可以看到MySQL8.0.26默认的存储引擎是InnoDB

设置系统默认的存储引擎
查看默认的存储引擎:
show variables like '%storage_engine%';
设置默认的存储引擎:
SET DEFAULT_STORAGE_ENGINE=InnoDB;创建表的时候使用的是默认的存储引擎(未显式指明),同时可以显式指明存储引擎
CREATE TABLE 表名( 建表语句; ) ENGINE = 存储引擎名称;
修改表的存储引擎:
ALTER TABLE 表名 ENGINE = 存储引擎名称;
存储引擎之间的区别
InnoDB存储引擎
- MySQL5.5之后默认的存储引擎就是InnoDB
- 支持事务,可以确保事务的完整提交和回滚,即使出现了宕机。
- 支持行锁,适合高并发操作。
- 支持外键
- InnoDB是
为处理巨大数据量的最大性能设计。 - 数据文件结构
- 表名.frm 存储表结构(MySQL8.0时,合并在表名.ibd中)
- 表名.ibd 存储数据和索引
- 缺点
- 对比MyISAM,InnoDB写的效率稍差(对于数据量比较小,只有增加和查询的情况下),并且会占用更多的磁盘空间以保存数据和索引
- 对内存要求较高,因为相比MyISAM只缓存索引,InnoDB不仅需要缓存索引还需要缓存真实数据。
MyISAM存储引擎
- MySQL5.5之前默认的存储引擎
- MyISAM提供了大量的特性,包括全文索引、压缩、空间函数(GIS)等,但
MyISAM 不支持事务、行级锁、外键 ,有一个毫无疑问的缺陷就是 崩溃后无法安全恢复 。 - 优势是访问速度快,对事务没有完整性要求或者以SELECT和INSERT为主
- 针对数据统计有额外的常数存储。故而 count(*) 的查询效率很高
- 数据文件结构
- 表名.frm 存储表结构
- 表名.MYD 存储数据 (MYData)
- 表名.MYI 存储索引 (MYIndex)
- 应用场景:只读应用或者以读为主的业务
- MyISAM和InnoDB对比

Archive引擎:用于数据存档
archive是归档的意思,仅支持插入和查询两种功能。- MySQL5.5之后支持
- 拥有很好的压缩机制,使用zlib压缩库,在请求的时候进行实时压缩,经常被用来作为仓库使用
- 文件架构:
表名.ARZ - 同样数据量下,Archive占据更小的磁盘空间
- 采用行级锁,支持AUTO_INCREMENT列属性。此列可以创建唯一索引或者非唯一索引。在其他列上创建索引会导致错误。
- 适合用于日志和数据采集(档案)类应用
CSV引擎
- CSV引擎可以将普通的CSV文件作为MySQL的表处理,但不支持索引
- CSV可以作为一种数据交换的机制
- CSV存储的数据可以慧姐放在操作系统中,用excel读取或者文本编辑器
- 常用于数据的导入导出
- 演示
查看文件结构:
```mysql CREATE TABLE test (id INT NOT NULL, name CHAR(10) NOT NULL) ENGINE = CSV; # 使用CSV引擎
INSERT INTO test values(1,’Tom’),(2,’Jerry’); # 插入数据 ```
.CSM存储的是表的元数据
.CSV就是我们常见的CSV文件,存储的是数据,每一列用”,“隔开
Memory引擎: 将数据存储到内存中
- Memory采用的逻辑介质是 内存 , 响应速度很快 ,但是当mysqld守护进程崩溃的时候 数据会丢失 。另外,要求存储的数据是数据长度不变的格式,比如,Blob和Text类型的数据不可用(长度不固定的)。
- Memory同时 支持哈希(HASH)索引 和 B+树索引 。 Memory表至少比MyISAM表要 快一个数量级 。
- MEMORY 表的大小是受到限制 的。表的大小主要取决于两个参数,分别是 max_rows 和
max_heap_table_size 。其中,max_rows可以在创建表时指定;max_heap_table_size的大小默
认为16MB,可以按需要进行扩大。 - 数据文件和索引文件分开存储
- 缺点:其数据易丢失,生命周期短。基于这个缺陷,选择MEMORY存储引擎时需要特别小心。
- 使用场景:
- 目标数据比较小 ,而且非常 频繁的进行访问 ,在内存中存放数据,如果太大的数据会造成 内存溢 出 。可以通过参数 max_heap_table_size 控制Memory表的大小,限制Memory表的最大的大小。
- 如果 数据是临时的 ,而且 必须立即可用 得到,那么就可以放在内存中。
- 存储在Memory表中的数据如果突然间 丢失的话也没有太大的关系 。


