MySQL中SQL的执行流程
MySQL中SQL的执行流程
1.MySQL查询流程
查询缓存:如果再查询缓存中发现了这条语句,就会直接返回给客户端,如果没有,就进入解析器阶段。
需要说明的是,因为查询缓存效率不高,命中率很低,所以在MySQL8.0中就抛弃了这个功能。
原因:
a.大多数情况查询缓存是个鸡肋,查询缓存是把sql语句和结果以key=value的方式缓存起来的,只有完全一直才能命中,如果多一个空格都不能命中,而且如果使用now()等函数,也会导致不能命中。
b.在对表进行修改,删除操作时,会删除所有该表的高速查询缓存,对于更新频繁的数据库来说,查询缓存的命中率非常低。
c.在静态表中可以使用查询缓存,可以在my.cnf中将参数query_cache_type
设置成demand,代表在sql语句中有SQL_CACHE
关键词时才缓存。
query_cache_type = 2 # 0 关闭 1 开启 2 demand(按需使用)
例:select SQL_CACHE * from table_test;
2.解析器:在解析其中对SQL语句进行语法解析,语义解析。
如果没有命中查询缓存,就要开始真正的执行语句了。首先,MySQL需要知道你想做什么,所以需要先对SQL语句进行解析,SQL语句的分析分为词法分析
和语法分析
。
● 词法分析:你输入的sql语句是一个字符串,如select * from test;
,分析器需识别出sql语句中每个字符串分别代表什么,比把如select关键字识别出来,代表查询语句,test识别成表名。
● 语法分析:根据词法分析的结果,语法分析起会根据语法规则,判断这个sql语句是否满足MySQL语法。如果你的语句不对,则会收到“you have a error in your sql syntax”的错误。
比如:select * fro test;则会报错。
如果SQL语句正确,则会生成一个这样的语法树。
- 下面是SQL词法分析的过程步骤
3.优化器:在优化器中会确定SQL语句的执行路径,比如是根据全表索引
,还是根据检索索引
等。
一条sql语句有很多种执行方式,最后都返回相同的结果,优化器的作用就是找到这其中最好的执行计划。
比如,在一个表内有多个索引时,决定是用哪个索引,或者在一个语句有多个表(join)的时候,决定各个表的连接顺序,还有表达式简化,子查询转为连接,外链接转为内链接 。
举例:如下语句是执行两个表的join
select * from test1 join test2 using(ID)
where test1.name = 'zhangsan' and test2.name = 'lisi'
- 方案1:可以先从表test1中取出name=zhangsan的数据对应的ID值,再根据ID取出test2表中的记录,在判断test2记录中的name是不是等于lisi。
- 方案2:可以先从test2中取出name=lisi的数据对应的ID值,再根据ID取出test1表中对用的数据记录,在判断test1记录中的name是不是等于zhangsan。
这两种方案返回的结果都是一样的,但是执行效率会有不同,而优化器的作用就是决定使用哪一种方案。优化器阶段完成后,这个语句的执行方案就确定下来了,然后就进入执行器阶段。
在查询优化器中,可分为逻辑查询
优化阶段和物理查询
优化阶段。
● 逻辑查询优化:通过改变sql语句的内容来使得sql查询效率更高,同时为物理查询优化提供更多的候选执行计划。
● 物理查询优化:基于关系代数进行的查询重写,而关系代数的每一步都对应着物理计算,这些物理计算往往存在多种算法,因此需要计算各种物理路径的代价,从中选择代价最小的作为执行计划。
4.执行器:截止到现在,还没有真正的读写真实的表,仅仅产出了一个执行计划。于是就进入了执行器阶段
在执行前需要判断该用户是否拥有权限。如果没有,返回权限错误信息。如果有权限, 就执行sql查询并返回结果。如果在MySQL8.0之前的版本,如果设置了查询缓存,这时将查询结果进行缓存。
如果有权限,就打开表继续执行。打开表的时候,执行器会根据表的引擎定义,调用存储引擎的API对表进行的读写。存储引擎API只是抽象的接口,下面还有个存储引擎层,具体实现还要看表选择的引擎。
比如:在test表中,ID没有索引,sql语句select * from test where ID = 1,那么执行器的执行流程是这样的:
- 调用InnoDB引擎接口取test表的第一行,判断ID是不是等于1,如果等于,则将这行存在结果集中,不等于则跳过,一直重复到表的最后一行。
- 执行器将上述过程中所有满足的行组成记录集,作为结果返回给客户端。
- 至此,这个语句就执行完了,对于有索引的表,只进行索引检索,而不是全标检索,执行逻辑也差不多。
SQL语句在MySQL中的流程是:SQL语句->查询缓存->解析器->优化器->执行器。
5.MySQL8中的执行原理
不同的DBMS的SQL执行原理是相同的,只不过在不同的软件中,各有各的实现路径。
既然一条sql语句会经历不同的模块,那我们可以看下在不同模块中,sql执行所使用的资源(时间)是怎样的。
如何在MySQL中对一条sql语句的执行时间进行分析。
1.确认profiling是否开启。
了解查询语句的底层执行过程:select @@profiling
或者show variables like '%profiling%'
。查看是否开启计划。开启它可以让MySQL收集sql语句在执行时所使用的资源情况,命令如下:
2.开启profiling
临时开启:set profiling = 1;
3.查看sql语句执行效率
查看所有语句:show profiles;
查看最新一条语句详情: show profile;
查询具体某一条详情:show profile for query 3;
4.开启查询缓存,执行两次同样sql语句查看profile
5.还可以查看cpu,io阻塞等情况
show profile
[type [,type] ...]
[for query n]
[limit row_count [offset offset]]
type{
all --显示所有参数
block io --显示io相关开销
context switchs --显示上下文切换相关开销
cpu --显示cpu相关开销
ipc --显示接受和发送相关开销
memory --显示内存相关开销
page faults --显示页面错误相关开销
source --显示和source_function,source_file,source_line相关开销
swaps --显示交换次数相关开销
}