基础架构
MySQL 可以分为 Server 层和存储引擎层两部分。
Server 层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等), 所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。
存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持 InnoDB、MyISAM、Memory 等多个存储引擎。 现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开始成为了默认存储引擎
你执行 create table 建表的时候,如果不指定引擎类型,默认使用的就是 InnoDB。
跟着 逻辑架构图 , 走一遍整个执行流程, 依次看下每个组件的作用。
连接器
连接器负责跟客户端建立连接、获取权限、维持和管理连接。
建立连接
在完成经典的 TCP 握手后,连接器就要开始认证你的身份,这个时候用的就是你输入的用户名和密码.
- 如果用户名或密码不对,你就会收到一个"Access denied for user"的错误,然后客户端程序结束执行。
- 如果用户名密码认证通过,连接器会到权限表里面查出你拥有的权限。之后,这个连接里面的权限判断逻辑,都将依赖于此时读到的权限。
一个用户成功建立连接后,即使你用管理员账号对这个用户的权限做了修改,也不会影响已经存在连接的权限。修改完成后,只有再新建的连接才会使用新的权限设置。 建立链接的最长时间是 8 小时, 由参数 wait_timeout
控制.
尽可能的使用长连接
建立连接的过程通常是比较复杂并且耗时的,在使用中要尽量减少建立连接的动作,也就是尽量使用长连接。
全部使用长连接后,你可能会发现,有些时候 MySQL 占用内存涨得特别快,这是因为 MySQL 在执行过程中临时使用的内存是管理在连接对象里面的。这些资源会在连接断开的时候才释放。所以如果长连接累积下来,可能导致内存占用太大,被系统强行杀掉(OOM),从现象看就是 MySQL 异常重启了。
如何合理地使用长连接 ?
- 定期断开长连接。使用一段时间,或者程序里面判断执行过一个占用内存的大查询后,断开连接,之后要查询再重连。
- 如果你用的是 MySQL 5.7 或更新版本,可以在每次执行一个比较大的操作后,通过执行 mysql_reset_connection 来重新初始化连接资源。这个过程不需要重连和重新做权限验证,但是会将连接恢复到刚刚创建完时的状态
查询缓存
查询缓存仅限于 MySQL < 8.0, 在 MySQL 8.0 以上版本, 查询缓存被移除掉了
连接建立完成后,你就可以执行 select 语句了。执行逻辑就会来到第二步:查询缓存。
如何使用查询缓存
MySQL 拿到一个查询请求后,会先到查询缓存看看, 如果你的查询能够直接在这个缓存中找到 key,那么这个 value 就会被直接返回给客户端。
查询缓存什么时候失效?
只要有对一个表的更新,这个表上所有的查询缓存都会被清空。
由于数据库经常做更新操作, 对于大多数情况来说, 查询缓存的命中率会非常低, 而对于系统配置表等更新频率地的表, 查询缓存的命中率会比较高, 但对于这类数据, 使用 redis / guava 等缓存层效果更优.
不要使用查询缓存, 查询缓存往往弊大于利
分析器
如果没有命中查询缓存,就要开始真正执行语句了。 首先进行的就是分析器对 SQL 语句做解析。
- 词法分析, 分析出 SELECT / INSERT 等关键字, 表名, 列名等等.
- 语法分析, 如果语句不对,就会收到“You have an error in your SQL syntax”的错误提醒
优化器
经过了分析器,MySQL 就知道你要做什么了。需要优化器来觉得怎么做才是最优操作.
不同的处理逻辑都能拿到相同的结果, 但是执行的效率会有不同,
比如. 表里面有多个索引的时候,决定使用哪个索引. 在一个语句有多表关联(join)的时候,决定各个表的连接顺序。
优化器的作用就是决定选择使用哪一个方案是最优(并不绝对)的方案。
执行器
经过了优化器, 就进入了执行器阶段.
- 权限验证. 开始执行的时候,要先判断一下你对这个表 T 有没有执行的权限.
- 通过条件扫描筛选并确定出指定的行
- 再根据查询字段返回需要返回的值.
索引可以使用在第二步来提升查询速度
对于扫描行数过多的 SQL 执行, 会在数据库的慢查询日志中看到一个 rows_examined 的字段,表示这个语句执行过程中扫描了多少行。这个值就是在执行器每次调用引擎获取数据行的时候累加的。