赞
踩
当希望Mysql能够高效的执行的时候,最好的办法就是清楚的了解Mysql是如何执行查询的,只有更加全面的了解SQL执行的每一个过程,才能更好的进行SQl的优化。
当执行一条查询的SQl的时候大概发生了一下的步骤:
Mysql的执行的流程图如下图所示:
这里以一个实例进行说明Mysql的的执行过程,新建一个User表,如下:
- // 新建一个表
- DROP TABLE IF EXISTS User;
- CREATE TABLE `User` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `name` varchar(10) DEFAULT NULL,
- `age` int DEFAULT 0,
- `address` varchar(255) DEFAULT NULL,
- `phone` varchar(255) DEFAULT NULL,
- `dept` int,
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=40 DEFAULT CHARSET=utf8;
-
- // 并初始化数据,如下
- INSERT INTO User(name,age,address,phone,dept)VALUES('张三',24,'北京','13265543552',2);
- INSERT INTO User(name,age,address,phone,dept)VALUES('张三三',20,'北京','13265543557',2);
- INSERT INTO User(name,age,address,phone,dept)VALUES('李四',23,'上海','13265543553',2);
- INSERT INTO User(name,age,address,phone,dept)VALUES('李四四',21,'上海','13265543556',2);
- INSERT INTO User(name,age,address,phone,dept)VALUES('王五',27,'广州','13265543558',3);
- INSERT INTO User(name,age,address,phone,dept)VALUES('王五五',26,'广州','13265543559',3);
- INSERT INTO User(name,age,address,phone,dept)VALUES('赵六',25,'深圳','13265543550',3);
- INSERT INTO User(name,age,address,phone,dept)VALUES('赵六六',28,'广州','13265543561',3);
- INSERT INTO User(name,age,address,phone,dept)VALUES('七七',29,'广州','13265543562',4);
- INSERT INTO User(name,age,address,phone,dept)VALUES('八八',23,'广州','13265543563',4);
- INSERT INTO User(name,age,address,phone,dept)VALUES('九九',24,'广州','13265543564',4);
-
- 12345678910111213141516171819202122232425

现在针对这个表发出一条SQl查询:查询每个部门中25岁以下的员工个数大于3的员工个数和部门编号,并按照人工个数降序排序和部门编号升序排序的前两个部门。
- SELECT dept,COUNT(phone) AS num FROM User WHERE age< 25 GROUP BY dept HAVING num >= 3 ORDER BY num DESC,dept ASC LIMIT 0,2;
- 1
开始执行这条sql时,会检查该语句是否有权限,若是没有权限就直接返回错误信息,有权限会进行下一步,校验权限的这一步是在图一的连接器进行的,对连接用户权限的校验。
相连建立之后,履行查询语句的时候,会先行检索内存,Mysql会先行冗余这个sql与否履行过,以此Key-Value
的形式平缓适用内存中,Key是检索预定
,Value是结果集
。
假如内存key遭击中,便会间接回到给客户端,假如没命中,便会履行后续的操作,完工之后亦会将结果内存上去,当下一次进行查询的时候也是如此的循环操作。
分析器主要有两步:(1)词法分析
(2)语法分析
词法分析主要执行提炼关键性字
,比如select,提交检索的表
,提交字段名
,提交检索条件
。语法分析主要执行辨别你输出的sql与否准确
,是否合乎mysql的语法
。
当Mysql没有命中内存的时候,接着执行的是 FROM student 负责把数据库的表文件加载到内存中去,WHERE age< 60
,会把所示表中的数据进行过滤,取出符合条件的记录行,生成一张临时表,如下图所示。GROUP BY dept
会把上图的临时表分成若干临时表,切分的过程如下图所示:
查询的结果只有部门2和部门3才有符合条件的值,生成如上两图的临时表。接着执行SELECT后面的字段
,SELECT后面可以是表字段
也可以是聚合函数
。
这里SELECT的情况与是否存在GROUP BY
有关,若是不存在Mysql直接按照上图内存中整列读取。若是存在分别SELECT临时表的数据。
最后生成的临时表如下图所示:
紧接着执行HAVING num>2
过滤员工数小于等于2的部门,对于WHERE
和HAVING
都是进行过滤,那么这两者有什么不同呢?
第一点是WHERE后面只能对表字段进行过滤,不能使用聚合函数,而HAVING可以过滤表字段也可以使用聚合函数进行过滤。
第二点是WHERE是对执行from USer操作后,加载表数据到内存后,WHERE是对原生表的字段
进行过滤,而HAVING是对SELECT后的字段进行过滤
,也就是WHERE不能使用别名进行过滤
。
因为执行WHERE的时候,还没有SELECT,还没有给字段赋予别名。接着生成的临时表如下图所示:
最后在执行ORDER BY后面的排序
以及limit0,2
取得前两个数据,因为这里数据比较少,没有体现出来。最后生成得结果也是如上图所示。接着判断这个sql语句是否有语法错误
,关键性词与否准确
等等。
查询优化器会将解析树转化成执行计划。一条查询可以有多种执行方法,最后都是返回相同结果。优化器的作用就是找到这其中最好的执行计划
。
生成执行计划的过程会消耗较多的时间,特别是存在许多可选的执行计划时。如果在一条SQL语句执行的过程中将该语句对应的最终执行计划进行缓存。
当相似的语句
再次被输入服务器时,就可以直接使用已缓存的执行计划
,从而跳过SQL语句生成执行计划的整个过程,进而可以提高语句的执行速度。
MySQL使用基于成本的查询优化器。它会尝试预测一个查询使用某种执行计划时的成本,并选择其中成本最少的一个。
由优化器生成得执行计划,交由执行器进行执行,执行器调用存储引擎得接口,存储引擎获取数据并返回,结束整个查询得过程。
这里之讲解了select的过程,对于update这些修改数据或者删除数据的操作,会涉及到事务,会使用两个日志模块,redo log和binlog日志。具体对这两个日志的介绍请看着一篇文章。
以前的Mysql的默认存储引擎MyISAM引擎是没redo log的,而现在的默认存储引擎InnoDB引擎便是透过redo 复杂度来拥护事务的,保证事务能够准确的回滚或者提交,保证事务的ACID。
1、一条查询SQL执行流程图
2、查询SQL执行流程之发送SQL请求
(1)客户端按照Mysql通信协议将SQL发送到服务端,SQL到达服务端后,服务端会单起一个线程执行SQL。
(2)执行时Mysql首先判断SQL的前6个字符是否为select。并且语句中是否带有SQL_NO_CACHE关键字,如果没有则进入查询缓存。
3、查询SQL执行流程之查询缓存
查询缓存说白了就是一个哈希表,将执行过的语句及其结果以键值对的格式缓存到内存中。其中key是一个哈希值,由查询SQL、当前要查询的数据库、客户端协议版本等生成的,value就是查询结果。如果要绕过查询缓存,可以在SQL中加SQL_NO_CACHE字段,如:
SELECT SQL_NO_CACHE * FROM table
注:Mysql8.0版本开始取消查询缓存
4、查询SQL执行流程之解析器
解析器执行流程分为两个阶段,词法解析和语法解析
(1)首先对SQL词法进行分析,将SQL从左到右一个字符、一个字符地输入,然后根据构词规则识别单词。将会生成4个Token,如下所示:
(2)然后对SQL语法进行解析,判断客户端传入的SQL语句是否满足Mysql语法。此时会生成一颗语法树,如下所示:
如果语法不对,将会收到如下提示
You have an error in your SQL syntax
如果解析器顺利生成语法树,就会将SQL送发到预处理器
5、查询SQL执行流程之预处理器
预处理器主要做两件事情,查看SQL中列名是否正确和权限验证
(1)首先判断SQL语句中的列名是否存在于数据表中,再看看表名是否正确,如果不对,将返回如下错误提示
Unknown column xxx in ‘where clause’
(2)预处理器对SQL进行权限验证,判断SQL是否有操作这个表的权限,若没有,则会返回如下错误信息
ERROR 1142 (42000): SELECT command denied to user 'root'@'localhost' for table 'xxx'
一切验证通过后将语法树传递给优化器
6、查询SQL执行流程之优化器
优化器的任务就是对SQL语句进行优化,达到最快的执行效果,优化器对SQL优化完成后会将SQL变成一个执行计划交给执行器
7、查询SQL执行流程之执行器
执行器就是根据执行计划来进行执行查询, 根据SQL的指令,逐条调用底层存储引擎,逐步执行。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。