跳到主要内容

MySQL 执行流程

客户端 ---TCP连接---> 连接器 -> 查询缓存 -> 词法分析 -> 语法分析 -> 语法树 -> 预处理器 -> 优化器 -> 执行计划 -> 执行器 -> 存储引擎

连接器

与 mysql 建立连接的过程?

通过 mysql -h$ip -u$user -p 连接 MySQL 服务。连接的过程需要先经过 TCP 三次握手。因为 MySQL 是基于 TCP 协议进行传输的。 完成 TCP 连接的建立后,连接器开始验证用户名和密码是否正确,如果用户名和密码没有问题,连接器会获取该用户的权限,然后保存起来, 后续在该用户在连接的任何操作,都会基于连接开始时读到的权限进行权限逻辑的判断

这就解释了,为什么修改用户的权限之后,没有立即生效,因为权限的判断是基于创建连接时读取到的权限。如果想让权限立即生效,需要执行 flush privileges. 或者重新登录即可获取到最新的权限。

空闲连接会一直占用着吗?

通过 show processlist; 可以查看哪些连接处于空闲状态。空闲连接达到一定的时间之后会自动断开。通过 show variables like '%wait_timeout%'; 来查看这个最大空闲时长。并且,这个连接断开时,客户端并不会第一时间直到,只有等待客户端发起下一次请求时,才会收到连接断开的报错。

MySQL 的连接数有限制吗?

有,通过 show variables like 'max_connections'; 命令查看最大连接数。

mysql 的长连接和短连接

  • 短连接
    • 连接 mysql 服务 (TCP 三次握手)
    • 执行 sql
    • 断开 mysql 服务 (TCP 四次挥手)
  • 长连接
    • 连接 mysql 服务 (TCP 三次握手)
    • 执行 sql
    • 执行 sql
    • ...
    • 断开 mysql 服务 (TCP 四次挥手)

使用长连接的优缺点?

可以减少建立连接和断开连接的次数。 但使用长连接过多时,会导致 mysql 占用内存增多。 mysql 在执行查询过程中临时使用内存管理连接对象,这些连接对象资源只有在断开连接时才会释放。 如果长连接累计很多,将导致 mysql 服务占用内存很大,有可能被操作系统强制杀掉,这回导致 mysql 服务异常重启。

如何解决长连接的内存占用问题?

  1. 定期断开长连接。
  2. 客户端主动重置连接。 在代码里调用 mysql_reset_connection()。这个过程不需要重新建立连接,会恢复到刚创建连接时的状态。

在建立连接时,连接器干了哪些工作?

  1. 与客户通过 TCP 三次握手,建立起 TCP 连接
  2. 检查用户名和密码
  3. 读取用户权限,后续在此连接的操作都基于此时读取到的权限。

查询缓存

MySQL 8.0 中以移除了缓存模块

客户端与 mysql 服务通过连接器建立连接后,客户端就可以向 mysql 服务发生 sql 语句了。mysql 服务在收到 sql 语句后,就会解析出 sql 语句的第一个字段, 看看是什么类型的语句。如果是查询语句,就会先去查询缓存里查找缓存数据,看看之前有没有执行过这条语句。

查询缓存是以 key-value 形式保存在内存的,key 为 sql 查询语句,value 为 sql 查询结果。

如果命中缓存,就直接将 value 返回给客户端。没有命中就继续往下执行,等执行完后,将查询结果存入查询缓存。

解析 SQL

正式执行 sql 查询语句之前,mysql 会先对 sql 进行解析。这个过程由解析器来完成。

解析器

  1. 词法分析
  2. 语法分析,构建语法树。不会去检查表或者字段存不存在。

执行 SQL

  1. prepare 阶段,预处理阶段
  2. optimize 阶段,优化阶段
  3. execute 阶段,执行阶段。

预处理器

  1. 检查 sql 查询语句中的表或字段是否存在
  2. SELECT * 中的 * 扩展为所有列。

优化器

优化器主要负责将 sql 查询语句的执行计划确定下来。(例如由多个索引时,决定选择哪个索引。)

通过 explain 命令来查看 sql 的执行计划。查询结果中的 key 列表示使用的索引; possible_keys 表示可以使用的索引;

  • key = null 表示全表扫描;
  • key = PRIMARY 表示使用主键索引。

执行器

优化器确定了执行计划之后,mysql 的执行器就真正开始执行语句了。执行器会与存储引擎交互,交互是以记录为单位。

执行 sql 之前先判断下权限。

慢查询日志中的 rows_examined 字段表示这个语句执行过程中扫描了多少行,在执行器每次调用引擎获取数据行的时候累加;

执行器和存储引擎的交互

  • 主键索引查询
  • 全表扫描
  • 索引下推

主键索引查询

全表扫描

索引下推

总结

简述下一条sql的执行过程

客户端通过 TCP 连接与 MySQL 服务建立连接,连接器在建立连接时会判断用户名和密码是否正确,如果不正确就返回异常。正确的话,会从数据库加载权限, 之后在此会话中执行的命令,都是基于此时读取到的权限。当客户端执行一条 sql 时,客户端通过之前建立的连接,sql 传给 MySQL 服务,mysql服务在接收到这条sql 后,会通过解析器,对这条 sql 进行词法解析和语法解析,生成一个语法树。解析无误之后,会通过预处理器来将 select * from ...* 替换为具体的列名并判断sql 中涉及到的表和字段是否存在和判断权限。然后,优化器会根据之前生成的语法树,确定好执行计划。执行器会根据执行计划,来调用 MySQL引擎的接口来执行 sql ,执行完成之后,会将查询到的数据返回给客户端。

需要注意的是:mysql 8.0 之前解析器在对sql 解析之前,会先去缓存里面判断下有没有这条查询 sql 缓存结果。但是在 mysql8.0 之后,这个缓存模块被移除了。