1. Mysql 中的sql执行流程
MySQL 的查询流程:
1. 查询缓存: Server 如果在查询缓存中发现了这条sql语句,就会直接将结果返回给客户端;如果没有,就进入到解析端。需要说明的是,因为查询缓存往往效率不高,所以在mysql8.0中废弃此功能。
大多数情况下查询缓存是个鸡肋,为什么?
查询缓存是提前把查询的结果缓存起来,这样下次不需要执行就可以直接拿到结果。需要说明的是,在mysql中的查询缓存,不是缓存查询计划,而是擦汗寻对应的结果。这就意味着查询匹配的鲁棒性大大降低,只有相同的查询操作才会命中查询缓存。两个查询请求在任何字符上的不同,都会导致缓存不会命中。因此mysql的查询缓存命中不高。
同时,如果查询请求中包含某些系统函数,用户自定义变量和函数,一些系统表,如mysql,information_schema, performance_schema 数据库中的表,那这个请求就不会被缓存。以某些系统函数举例,可能同样的函数的两次调用会产生不一样的结果,比如函数now,每次调用都会产生最新的当前事件,如果在一个查询中调用了这个函数,那即使查询请求的文本信息都一样,那不同的时间的两次查询也应该得到不同的记过,如果在第一次查询时就缓存了,那第二次查询的时候直接用第一次就是错误的。
此外,既然是缓存,那就有他的缓存失效, mysql缓存系统会检测设计到的每张表,只要该表的结构或者数据被修改,那使用该表的所有钙塑缓存查询都将变为无效并从缓存中删除!对于更新压力大的数据库来说,查询缓存的命中率会非常低。
总之,因为查询缓存往往利大于弊,查询缓存失效非常频繁。
2. 解析器:在解析器中对sql语句进行语法分析,语义分析。
分析器先做 ‘ 词法分析 ’。你输入的是由多个字符串和空格组成的一条sql语句,mysql 需要识别处里里面的字符串分别是什么,代表什么。
mysql从你输入的 select 这个关键字识别出来,这是一个查询语句。他也要把字符串 T 识别成表名 T,他字符串 ID 识别成列 ID。
接着,要做 ‘ 语法分析 ’。 根据词法分析的结果,语法分析器(比如:Bison)会根据语法规则,判断是输入的这个sql语句是否满足 mysql 语法。
如果你的语法不对,就会收到 ‘ You have an error in your sql syntax’ 的错误提醒
3. 优化器: 在优化器中会确定sql语句执行的路径,比如是根据全表检索,还是根据索引检索等。
经过了解析器,mysql就知道你要作什么了。在开始执行之前,还要先经过优化器的处理。一条查询可以有很多执行方式,最后都返回相同结果。优化器的作用就是找到这其中最好的执行计划。
比如:优化器是在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联join的时候,决定各表的连接顺序,还有表达式简化,子查询转为连接,外连接转为内连接等。
举例:
select * from test1 join test2 using(ID) where test1.name='zhangwei' and test2.name='mysql高级课程';
方案1:可以先从表test1里面取name='zhangwei' 的记录id,再根据id值关联到test2,在判断test2里面name='mysql高级课程'
方案1:可以先从表test2里面取name='mysql高级课程' 的记录id,再根据id值关联到test1,在判断test2里面name='zhangwei'
这两种执行方法的逻辑姐u共是一样的,但是执行的效率会有不同,而优化器的作用就是决定选择使用哪一个方案。优化器阶段完成后,这个语句的执行方案就确定下来了,然后进入执行器阶段。
在查询优化器中,可以分为 逻辑 查询优化 阶段和 物理查询 优化阶段。
3. 执行器:
在执行之前需要判断该用户是否具备权限。如果没有,就会返回权限错误,如果具备权限,就执行sql查询并返回结果。
如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,调用存储引擎api对表进行读写。存储引擎api只是个抽象接口,下面还有个存储引擎层,具体实现还是要看表选择的存储引擎。
sql语法顺序
select distinct # 手写顺序 <select_list> from < left_table > < join_type > join < right_Table > on < join_condition > where < where_condition > group by < group_by_list > having < having_condition > order by < order_by_condition > limit < limit_number > from < left_table > # 机器读取顺序 on < join_condition > < join_type > join < right_Table > where < where_condition > group by < group_by_list > having < having_condition > select distinct <select_list> order by < order_by_condition > limit < limit_number >
查看sql语句执行的历史记录
show profiles;
show profile; # 查看最近一条执行的sql详情 ( show profile for query 7; 查看指定的语句)
每个环节所花费的时间如下:
starting 开始状态
checking permissions 检查权限
opening tables 打开表
init 初始化
System lock 锁系统
optimizing 优化器
statistics 统计
preparing 准备
executing 执行
end 结束