查询语句是如何在mysql中执行的呢?mysql> select * from T where ID=10;
MySQL 的基本架构
MySQL Server架构自顶向下大致可以分 网络连接层、服务层、存储引擎层和 系统文件层。
简单结构
MySQL 可以分为 Server 层和存储引擎层 两部分
服务层: 包括连接器、查询缓存、分析器、优化器、执行器等
存储引擎层: 负责数据的存储和提取,5.6版本默认使 InnoDB, 在 create table 语句中可以使用 engine = memory 指定使用的存储引擎
服务层解析
1.连接器:
第一步,你会先连接到这个数据库上,这时候接待你的就是连接器。 连接器负责跟客户端建立连接、获取权限、维持和管理连接。
连接命令一般是这么写的: mysql -h$ip -P$port -u$user -p输入mysql -h -P -u -p命令是mysql客户端输入,是为了与服务端建立连接
- 完成TCP握手操作
- 验证用户密码
- 验证成功后,是查询权限表,获取用户权限,此连接后面的权限的逻辑判断,通过当前查询权限信息校验 ,权限修改,需要重新建立连接才生效
- 连接完成后,如果你没有后续的动作,这个连接就处于空闲状态,你可以在 show processlist 命令中看到它 show processlist : 显示哪些线程正在运行。
- 客户端如果太长时间没操操作,连接器就会自动将它断开。这个时间是由参数 wait_timeout 控制的,默认值是 8 小时。
短连接和长连接是怎么设置的?是连接数据库的时候有什么参数吗?
答: 不是, 这是“行为”,比如连接完,执行一个查询,就断开,这是短连接; 执行一个查询,不断开,下次查询还用这个连接,持续使用,就是长链接;
2.查询缓存
连接建立完成后,就可以执行 select 语句了。执行逻辑就会来到第二步:查询缓存。
连接成功后,sql语句会同时传给 查询缓存 和 分析器
如果缓存中没有匹配到,则分析器继续执行,到执行器才会真正被执行
如果能在缓存中匹配到该语句(sql语句为key ,查询结果为value),则会直接返回其value, 执行器里的该语句停止运行,
但是:不建议使用:查询缓存 (失效过于频繁,并且可以采用其他非关系型数据库代替)
查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查询缓存都会被清空;
如何按需使用查询缓存:将参数 query_cache_type 设置成 DEMAND, (0时表示关闭,1时表示打开 )这样对于默认的 SQL 语句都不使用查询缓存。对于确定要使用查询缓存的语句,可以用 SQL_CACHE 显式指定:mysql> select SQL_CACHE * from T where ID=10;
注意:MySQL 8.0 版本直接将查询缓存的整块功能删掉了,也就是说 8.0 开始彻底没有这个功能了。
have_query_cache 表示这个mysql版本是否支持查询缓存
query_cache_limit 表示单个结果集所被允许缓存的最大值
query_cache_min_res_unit 每个被缓存的结果集要占用的最小内存
query_cache_size 用于查询缓存的内存大小
query_cache_free_memory 查询缓存目前剩余空间大小
query_cache_hits 查询缓存的命中次数
query_cache_inserts 查询缓存插入的次数。
3.分析器
如果没有命中查询缓存,就要开始真正执行语句了。首先,MySQL 需要知道你要做什么,因此需要对 SQL 语句做解析。
分析器: 先 词法分析(表 字段 )---> 语法分析(sql 语法校验)--->生成解析
- 识别传进来的字符串
- 分析器先会做“词法分析”,MySQL 需要识别出里面的字符串分别是什么,代表什么。
- 做完了这些识别以后,就要做“语法分析”,根据词法分析的结果,语法分析器会根据语法规则,判断你输入的这个 SQL 语句是否满足 MySQL 语法。
- 如果有错误,将会收到You have an error in your SQL syntax的报错
具体:
解析器处理语法和解析查询, 生成一课对应的解析树。
预处理器进一步检查解析树的合法。比如: 数据表和数据列是否存在, 别名是否有歧义等。如果通过则生成新的解析树,再提交给优化器。
4.优化器
通过分析器,明白你要干啥后,数据库就要针对你的需求找出最优的解决方案,生成执行计划。这个最优方案选择的操作,这个就是优化器要做的事情了。
优化原则是:尽可能扫描少的数据库行纪录,减少查询的响应时间。 最终输出一个 执行计划
优化方式:
优化器是在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联(join)的时候,决定各个表的连接顺序
MySQL的查询优化器会考虑各种查询优化技术,包括索引、聚集索引、覆盖索引、索引合并、索引下推、子查询优化、连接优化等。
通过使用这些优化技术,MySQL可以提高查询的性能,减少查询的响应时间。
5.执行器
执行器根据优化器生成的执行计划进行sql语句的执行。 先校验权限-->调用存储引擎接口-->返回结果集
执行SQL语句前:
开始执行的时候,要先判断一下你对这个表 T 有没有执行查询的权限,如果没有,就会返回没有权限的错误,
mysql> select * from T where ID=10;ERROR 1142 (42000): SELECT command denied to user 'b'@'localhost' for table 'T'
如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。 与存储引擎进行打交道了
mysql> select * from T where ID=10;
比如我们这个例子中的表 T 中,ID 字段没有索引,那么执行器的执行流程是这样的:
调用 InnoDB 引擎接口取这个表的第一行,判断 ID 值是不是 10,如果不是则跳过,如果是则将这行存在结果集中;
调用引擎接口取“下一行”,重复相同的判断逻辑,直到取到这个表的最后一行。
执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端
对于有索引的表,执行的逻辑也差不多。
第一次调用的是“取满足条件的第一行”这个接口,之后循环取“满足条件的下一行”这个接口,
这些接口都是引擎中已经定义好的。
你会在数据库的慢查询日志中看到一个 rows_examined 的字段,表示这个语句执行过程中扫描了多少行。这个值就是:在执行器每次调用引擎获取数据行的时候累加的。
在有些场景下,执行器调用一次,在引擎内部则扫描了多行,因此引擎扫描行数跟 rows_examined 并不是完全相同的。我们后面会专门有一篇文章来讲存储引擎的内部机制,里面会有详细的说明。
mysql 查询流程图:
小结
今天我给你介绍了 MySQL 的逻辑架构,希望你对一个 SQL 语句完整执行流程的各个阶段有了一个初步的印象。
随堂测试:
如果表 T 中没有字段 k,而你执行了这个语句 select * from T where k=1, 那肯定是会报“不存在这个列”的错误: “Unknown column ‘k’ in ‘where clause’”。
你觉得这个错误是在我们上面提到的哪个阶段报出来的呢?