开发者基本都知道我们的数据存在于数据库中(目前最常见的是mysql和MySQL,由于笔者比较擅长mysql,所以这里默认的数据库是mysql)。 服务器通过sql语句将查询数据的请求传递到mysql数据库。 数据库获取到sql语句后。 进行了哪些操作? 在这里我想向大家介绍一下我个人的理解。 欢迎大家在评论区批评指正。
流程概览
mysql获取到sql语句后,大致流程如下:
1.SQL解析器:负责解析和转发SQL
2. 预处理器:验证解析后的sql树
3.查询优化器:获取执行计划
4.查询执行引擎:获取数据结果集
5. 将数据返回给调用端。
流程图如下:
分发器和缓存阶段
首先,如果系统的缓存功能开启,那么SQL语句进入mysql后,SQL会判断是否是关键字。 如果有,那么首先去查询缓存中查询。 如果该sql语句在查询缓存中能够命中,则直接返回查询缓存中该查询语句对应的值(在缓存中,对查询语句进行哈希运算,结果作为key值,查询结果集是值)。
如果命中缓存的话,查询速度还是相当快的。 但查询缓存也有其相应的缺点。
首先,如果开启缓存,服务器会消耗大量的内存空间; 其次,缓存有时不适用; 最后,在某些情况下,开启缓存不会将相应的SQL语句写入缓存中。
不适用缓存的情况:
缓存锁比较强,对动态SQL的支持不够。
当数据更新时,缓存执行表级锁。 更新完成后,所有与更新内容相关的缓存都会被删除。 因此,如果对表的写入次数很多,缓存就很浪费性能。 如果写入量很大,缓存实际上可能会导致mysql变慢。
当无法查询缓存时:
1、查询条件包含不确定的数据:比如now等。
2. 缓存区分大小写。 例如*和*FROM test不会被解析成同一个sql。
查询带来的额外开销:
1.开始之前需要检查缓存是否命中。
2、输出结果时,需要进行额外的数据缓存操作。
3、写入数据时,mysql会将对应表的所有缓存设置为无效。 当缓存内存较大时,会造成较大的系统消耗。
SQL 解析器和预处理
sql解析器在命令分发后将相应的sql语句解析成sql解析树。 sql解析树是Mysql本身内部的语法规则和解析查询。 验证是否使用了错误的关键字、SQL语法顺序是否正确等(语法错误)
解析完成后,对查询语句进行预处理,根据mysql的规则检查解析树是否合法。 (表是否存在,别名是否有歧义等)
查询优化器
查询优化器获取执行计划,然后查询执行引擎执行相应的操作。 查询优化器是数据库l的核心模块,分为cbo和rbo两种类型。
其中,rbo是基于规则的优化器。 (早期版本使用了rbo,现在保留,但默认是cbo。Mysql没有rbo优化器)
这些规则被硬编码在数据库的代码中。 rbo会使用输入的sql语句能够匹配的最高优先级规则作为执行计划。 例如:rbo中有这样一条规则:如果有索引,就使用索引。 那么所有有索引的表在执行时都会被索引。 rbo最大的问题是执行计划是由固定的规则决定的。 它没有考虑sql涉及的对象的数量和分布。 所选择的规则有可能不是最优的执行计划。
cbo是一个基于成本的优化器(基于统计信息),它从众多目标执行路径中选择成本最低的执行路径作为执行计划。 cost是指mysql根据相关统计信息计算出的sql语句对应的io、cpu等消耗的预估。 计算过程涉及索引、表、行等数据,过程相对复杂。
1.查询优化器使用统计信息来选择sql的执行计划。
2、Mysql没有数据柱状图,统计信息无法手动删除。 (有)
3、服务器上有查询优化器,但没有保存数据和索引统计信息。 统计信息由存储引擎实现,不同的存储引擎存储不同的统计信息。
4、统计信息分为索引统计信息和表统计信息。
查看统计数据
指数统计
或.表
表统计
或.表
查询执行引擎+返回数据给客户端
获取到执行计划后,根据已有的执行计划,查询执行引擎,mysql的SQL Layer层,调用Layer层的接口,从mysql的存储引擎中获取对应的结果集,然后返回给用户。
执行完成后,将结果返回给客户端。 如果是查询语句并且启用了缓存,那么MySQL会同时将结果集放入查询缓存中。 然后返回找到的结果集。 如果是增删改操作,则返回执行该语句后受影响的行数。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。