一条SQL的执行过程

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 一条SQL的执行过程

一条SQL的执行过程

在日常开发中,我们无论使用JDBC或者是可视化工具,执行SQL时,首先需要建立数据库连接,以JDBC为例,第一步加载jbcd驱动程序,接着建立连接,创建preparedStatement,执行SQL,最后处理返回结果,那么SQL在MySQL中做了什么操作呢?整个流程参考下面这张图

image.png

SQL执行流程

1.建立连接

下面开始SQL执行流程的第一步,建立连接,MySQL将连接器中的连接分为长连接和短连接。

长连接是指连接成功后,客户端请求一直使用同一个连接

短连接是指每次执行完SQL请求的操作之后会断开连接,如果再有SQL请求会重新建立连接。由于短连接会反复创建连接消耗相同资源,因此多数情况下会选择长连接。但是为了保持长连接,会占用系统内存

MySQL会在接收客户端的连接请求时,对客户端的身份权限进行检查,成功建立连接后才能继续往下进行,MySQL提供了一些连接参数供我们查看连接情况。

如何查看当前MySQL的连接(并发)数?

show global status like 'Thread%';

image.png

其中Thread_connected表示当前建立的连接数量,Threads_running表示当前运行着的线程数,大家可以多开几条连接,查看变化。

通过这行SQL,可以查看MySQL支持的最大连接数

show variables like 'max_connections';

image.png

需要调整最大并发数时,只需要改变这个值即可。

2.查询缓存

MySQL中存在一个缓存池,相当于将SQL作为key,查询的数据作为value保存在缓存池中,当下一次执行的SQL存在缓存池中时,直接取出缓存的数据返回,如果执行两次下面的语句,所需要的时间会一样吗?

select * from city where city_name = '杭州'

答案是不会的,因为MySQL默认缓存是关闭的,我们可以通过下面这条语句查看缓存开启情况

show variables like 'query_cache%'

image.png

MySQL为什么默认关闭缓存呢?主要是因为MySQL自带的缓存应用场景十分有限,首先它要求执行的SQL必须一模一样,就算中间有空格,或大小写不同都会导致缓存失效。另外,当表中的数据发生变化时,也会导致缓存失效。

这对于需要对大量数据进行更新操作的系统也不适用,所以缓存这块还是叫给数据库框架处理比较合适,例如Mybatis默认就开启了一级缓存,或者采用Redis等缓存中间件来实现更好一些,所以MySQL8.0也已经移除了缓存池。

MySQL如何判断缓存命中

再想一想,假设我们已经开启了缓存,再执行两次下面的SQL,第二次执行会不会命中缓存呢?

select * from city where create_date < CURRENT_DATE()

还是不会命中缓存,因为在包含一些不确定的函数时,不会被缓存,例如NOW()、CURRENT_DATE(),因为这些不确定的函数,使SQL变得不确定,另外,包含任何用户自定义的函数、存储过程、用户变量、临时表都不会被缓存。

如果希望带有一个日期的查询,那么最好将日期提前计算好

例如:

...DATE_SUB(CURRENT_DATE, INTERVAL 1 DAY) -- 不缓存
...DATE_SUB(2020-08-23, INTERVAL 1 DAY) --缓存

3.语法解析和预处理

如果上一步没有命中缓存,那么在这一步会进行词法和语法的分析

例如这条语句

select name from city where id = 1;

首先会将这条语句切分成8个字符,再进行语法分析,例如引号有没有闭合,关键字是否存在等检查,然后再根据SQL语句生成一棵解析树

image.png

到这一步说明SQL已经通过检查,那么如果我们表名写错了呢?MySQL怎么进行检查?这就要靠下一步的预处理器来检查了。

预处理器会根据生成的解析树对表名、列名、别名等进行检查,确保不会出现歧义后重新生成一棵新的解析树。

4.查询优化执行计划

通过验证的SQL,由优化器将其转换为执行计划,一条查询可以有很多种执行方式,最后都返回相同的结果,而优化器的作用就是找到其中最好的执行计划。

举两个简单的例子:1、当我们对多张表进行关联查询的时候,以哪个表的数据作为基准表。2、有多个索引可以使用的时候,选择哪个索引。实际上,对于每一种数据库来说,优化器的模块都是必不可少的,他们通过复杂的算法实现尽可能优化查询效率的目标。

如果我们想知道优化器是怎么工作的,它生成了几种执行计划,应该怎么做呢?首先,通过下面的语句开启优化器的追踪(默认是关闭的)

SHOW VARIABLES LIKE 'optimizer_trace';
set optimizer_trace='enabled=on';

接着我们执行一个 SQL 语句,优化器会生成执行计划,执行下面的语句查看执行计划

select * from information_schema.optimizer_trace

这是一个包含三个部分的 JSON 数据,分别是准备阶段、优化阶段和执行阶段。其中,优化阶段生成了经过优化的 SQL 语句,保存在 expanded_query 字段中;执行阶段则包含了所有被考虑的执行计划,保存在 considered_execution_plans 字段中。

打开优化器追踪的开关对性能影响比较大,在分析完后记得关掉它

set optimizer_trace='enabled=off';

5.执行引擎

到这一步,MySQL会通过执行引擎调用存储引擎的API来查询结果,为什么我们切换了存储引擎,却不会影响执行引擎查询数据呢?原因是因为这些存储引擎都是用相同的API来向执行引擎提供操作的,查询出最终的结果后,把结果返回给客户端,客户端再根据需要对结果进行处理或者显示

相关文章
|
6月前
|
SQL 缓存 关系型数据库
执行一个SQL,MySQL内部的执行过程是什么?
执行一个SQL,MySQL内部的执行过程是什么?
57 0
|
6月前
|
SQL Java 数据库连接
日志输出-查看 SQL:深入分析 MyBatis 执行过程
日志输出-查看 SQL:深入分析 MyBatis 执行过程
240 0
|
6月前
|
SQL 数据库 数据库管理
一条SQL语句的执行过程
一条SQL语句的执行过程
|
存储 SQL 缓存
MySQL 中一条 SQL 查询语句的执行过程
`SELECT id FROM table_a where id = 10` 这条 SQL 从执行到最后结果返回你知道都经历了哪些步骤么?
MySQL 中一条 SQL 查询语句的执行过程
|
SQL 缓存 Java
MyBatis核心源码深度剖析SQL执行过程
MyBatis核心源码深度剖析SQL执行过程
53 0
|
6月前
|
SQL 存储 缓存
【SQL】Mysql中一条sql语句的执行过程
【SQL】Mysql中一条sql语句的执行过程
84 0
|
6月前
|
SQL 关系型数据库 MySQL
|
SQL Java 关系型数据库
hive中 sql执行过程
hive中 sql执行过程
122 0
|
SQL 存储 缓存
一条查询SQL的执行过程
一条查询SQL的执行过程
118 1
|
SQL 缓存 自然语言处理
sql执行过程
还在等什么,快来一起讨论关注吧,公众号【八点半技术站】,欢迎加入社群
sql执行过程