本文基于 MySQL8 版本编写,如非注明,皆为MySQL8的特性。如若涉及旧版本内容会标注说明。
逻辑架构
MySQL 主要分为四个层级,分别是:连接层、核心服务层、存储引擎层、数据存储层。这四大层级包含以下几部分:连接池、管理服务和工具、SQL 接口、查询分析器、优化器、缓存和缓冲池、插件式存储引擎、物理文件,
一、连接层
从客户端到 MySQL 服务端建立的连接会有多个,不管客户端如何管理这些连接,MySQL 服务端都会维护一个连接池。
连接池中每个连接均含有身份、权限等验证,连接中的信息不会动态更新,也就是说如果某个连接的用户权限更改了,除非将它销毁再重连,否则权限是不会变化的。
使用SHOW FULL PROCESSLIST可查看全部连接的状态信息。
连接池中一般关注两个参数:wait_timeout和max_allowed_packet。
wait_timeout参数:连接空闲超时断开的时间,默认值:8小时。当连接空闲的时间超过该值时,服务端主动断开该连接。
max_allowed_packet参数:客户端请求携带数据最大值,默认值:64M(5.7等旧版本默认值为4M,具体的值可以通过show VARIABLES like '%max_allowed_packet%';查看)。客户端给 MySQL 发送请求时,请求中携带的数据,被允许的最大值即由该参数控制。如果觉得该值不满足业务需求,可以自行更改。
二、核心服务层
客户端与 MySQL 建立连接后,就开始进入核心服务层。SQL语句在核心服务层可能经历如下事情:
查询缓存
从 MySQL8.0 开始已经删除查询缓存功能。如果是 MySQL5.7 等旧版本且开启了查询缓存,会优先检查是否命中缓存,命中缓存则直接返回缓存中的数据给客户端,否则进入下一步。由于每次表更新都会导致缓存失效,所以失效率很高,不建议开启查询缓存。
分析器
分析器会解析SQL,检查SQL语法的合法性,语法有问题的语句会返回异常给客户端。然后对语句进行预处理,主要检查表、字段、别名等的合法性。最后还要验证权限等安全问题。
优化器
优化器会给语句生成执行计划,同一个SQL语句可以有多个执行计划,最终获得相同的结果。但是这些执行计划的性能会有差异,优化器通过评估成本选择它认为最好的执行计划。然而,总会有各种原因导致优化器选择的不是最好的计划甚至有可能选择到很差的计划,这些事情发生时需要特别调整SQL使得优化器选择到我们满意的计划。
优化器还会对我们的SQL做出许多优化,诸如:
- 重定义关联表顺序,降低驱动表使用不当导致的性能问题
- 外连接可能转为内连接
- 优化内置函数的计算,COUNT()、SUM()等
- 覆盖索引扫描:当在辅助索引上就能完成查询需求时,直接使用辅助索引的数据返回
- 子查询优化
- 提前终止查询,发现已满足查询需求时,例如 limit n
- 等值传播:两个列的值通过等式关联,where 条件会将一个列的值传到另一列
- IN()的优化:先排序IN()的列表数据,再用二分法确定IN()的列表数据是否满足条件
在语句钱加上 EXPLAIN EXTENDED,语句后加上 SHOW WARNINGS 就可以查看优化器重构后的语句。
三、存储引擎层
这层里有各种存储引擎供我们选择,诸如 MyISAM、InnoDB 等,通过提供API跟上一层(核心服务层)配合工作,这些API可以隐藏各个存储引擎的差异,类似于Java里的面向接口编程,实现类不同会有不同的效果。
InnoDB 引擎是使用最广泛的,如非必要不需要考虑其他引擎。
四、数据存储层
文件系统组件在这层里,是实际存储数据的地方,包含数据文件、日志文件、配置文件等。
1、数据文件
可以使用 SHOW VARIABLES LIKE '%datadir%'; 命令查看数据文件的目录,在数据文件目录下我们可以看到如下的一些文件。
-
auto.cnf:MySQL启动时,会自动从data_dir/auto.cnf 文件中获取server-uuid值,并将这个值存储在全局变量server_uuid中。如果这个值或者这个文件不存在,那么将会生成一个新的uuid值,并将这个值保存在auto.cnf文件中。这个uuid的作用是在mysql复制时如果发生故障,slave可以通过uuid辨识master的日志。 -
binlog.index:用于记录MySQL产生的binlog日志的具体位置,binlog是MySQL记录所有操作的逻辑日志,主要用于故障恢复和主从同步时使用,由于MySQL数据库是一个多类型存储引擎并存的数据库,binlog就起着一个实例(instance)总体重做信息的角色。 -
*.pem文件:MySQL8新加入文件,用于ssl认证登陆 -
ib_buffer_pool:mysql innodb buffer pool 预热,当 mysql 数据库 innodb buffer pool 达到一定量级之后再异常宕机重启之后,就会面临一个严峻的问题,就是如何快速预热 buffer pool,光靠 innodb 是不够的,这时就需要将 innodb buffer pool 存储到存储中,在数据文件中进行备份,在重启时 innodb 直接读取此文件,但是要保证 innodb 版本 page 页大小,buffer pool 大小前后一致。-
innodb_buffer_pool_dump_at_shutdown:默认为关闭OFF。如果开启该参数,停止MySQL服务时,InnoDB将InnoDB缓冲池中的热数据保存到本地硬盘。 -
innodb_buffer_pool_load_at_startup:默认为关闭OFF。如果开启该参数,启动MySQL服务时,MySQL将本地热数据加载到InnoDB缓冲池中。 -
innodb_buffer_pool_load_now:默认为关闭OFF。如果开启该参数,停止 MySQL 服务时,需要以手动方式将 InnoDB 缓存池中的热数据保存到本地硬盘。 -
innodb_buffer_pool_load_abort:默认为关闭OFF。如果开启该参数,即便开启 InnoDB 预热功能,启动MySQL服务时,MySQL 也不会将本地硬盘的热数据加载到 InnoDB 缓冲池中。 -
innodb_buffer_pool_filename:如果开启InnoDB预热功能,停止MySQL服务时,MySQL将InnoDB缓冲池中的热数据保存到数据库根目录中,默认文件名为ib_buffer_pool.
-
-
ibdata1:innodb默认共享表空间,在不指定下默认所有表共享一个表空间,但是一般生产环境中建议修改默认值,每个表一个表空间 -
.ibd:使用独享表空间存储表数据和索引信息,一张表对应一个ibd文件 -
ib_logfile*:innodb 的 redo log 日志,区别于 binlog,由于 mysql 是一个支持多存储引擎共存的数据库,所以 innodb redo 只记录 innodb 存储引擎的重做日志,并且 redo 是一个物理日志,通过 xid 记录数据文件位置和 binlog 中的位置,而 binlog 记录的是 mysql 全局的变化量,是一个逻辑日志。实际中 mysql 中由于两阶段 commit 的存在弱化了 innodb redo 的管理,也不需要像 Oracle 中需要备份 redo 日志,mysql 中只需要备份 binlog 日志即可。 -
ibtmp1:innodb 临时表空间 -
undo_001:innodb undo表空间
2、日志文件
常用的日志包括:错误日志、二进制日志、查询日志、慢查询日志和事务redo日志、中继日志等等。
可以通过 SHOW VARIABLES LIKE '%_log_%'; 查询当前MySQL日志使用情况。
3、配置文件
用于存放MySQL所有的配置信息的文件,比如:my.cnf、my.ini 等。
可以使用 mysql --help|grep my.cnf 查看MySQL配置文件的位置:
MySQL是以 /etc/my.cnf -> /etc/mysql/my.cnf -> /usr/etc/my.cnf -> ~/.my.cnf 的顺序读取配置文件的,如果有相同的配置,会以读取到的最后一个配置文件中的参数为准。