当前位置: 首页 > 后端技术 > Java

面试官:MySQL是如何执行一条查询语句的?

时间:2023-04-01 16:14:21 Java

对于一个开发工程师来说,我觉得非常有必要了解MySQL是如何执行一条查询语句的。首先我们要了解MYSQL的架构是什么样的?那我们来说说一条查询语句的执行过程?MYSQL架构先看一张架构图,如下:模块详解Connector:用于支持各种语言与SQL的交互,如PHP、Python、Java的JDBC;ManagementServices&Utilities:系统管理和控制工具,包括备份和恢复、MySQL复制、集群等;ConnectionPool:连接池,管理需要缓冲的资源,包括用户密码权限线程等;SQL接口:用于接收用户SQL命令,返回用户需要的查询结果;Parser:用于解析SQL语句;优化器:查询优化器;Cache和Buffer:查询缓存,除了行记录缓存,还有表缓存、键缓存、权限缓存等;PluggableStorageEngines:插件式存储引擎,提供API供服务层处理特定文件使用。架构分层将MySQL分为三层,与客户端接口的连接层,实际执行操作的服务层,以及与硬件打交道的存储引擎层。连接层我们的客户端必须连接到MySQL服务器的3306端口,并且必须与服务器建立连接,然后管理所有的连接,验证客户端的身份和权限,这些功能都是在连接层完成的。服务层的连接层会将SQL语句传递给服务层,其中还包括一系列的过程:比如查询缓存的判断,根据SQL调用相应的接口,解析语法和文法等我们的SQL语句(如关键字如何识别,别名如何识别,是否有语法错误等)。然后是优化器。MySQL底层会按照一定的规则对我们的SQL语句进行优化,最后交给执行器执行。存储引擎存储引擎是我们的数据实际存储的地方。MySQL支持不同的存储引擎。接下来是内存或磁盘。SQL的执行过程以一条查询语句为例,我们来看看MySQL的工作流程是什么样的。从id=1且age>20的用户中选择名称;首先我们看一张图,接下来的流程是根据这张图:连接程序或工具需要操作数据库,第一步是与数据库建立连接。数据库中有两种连接:短连接:短连接在操作完成后立即关闭。长连接:长连接可以保持打开状态,减少服务器端创建和释放连接的消耗,后续程序访问时也可以使用这个连接。建立连接很麻烦。首先,您需要发送请求。发送请求后,需要验证账号密码。验证通过后,您需要检查您拥有的权限。因此,在使用过程中尽量使用长连接。保持持久连接会消耗内存。对于长时间不活动的连接,MySQL服务器将断开连接。可以使用sql语句查看默认时间:showglobalvariableslike'wait_timeout';这个时间是由wait_timeout控制的,默认是28800秒,8小时。查询缓存MySQL内部自带缓存模块。执行同样的查询后,我们发现缓存没有生效,为什么?默认情况下禁用MySQL缓存。显示像“query_cache%”这样的变量;默认关闭就是不推荐,为什么MySQL不推荐使用自己的缓存呢?主要原因是MySQL内置缓存的应用场景有限:首先是它要求SQL语句必须完全相同,中间多出一个空格,大小写不同的字母被认为是不同的SQL。二是当表中任意一条数据发生变化时,该表中的所有缓存都会失效,因此不适合数据更新量大的应用。所以,把缓存交给ORM框架(比如MyBatis默认开启一级缓存),或者独立的缓存服务,比如Redis,是比较合适的。在MySQL8.0中,查询缓存已被移除。语法分析和预处理为什么一条SQL语句可以被识别?如果随机执行字符串hello,服务器报1064错误:[Err]1064-你的SQL语法有错误;查看与您的MySQL服务器版本对应的手册,了解在第1行的“hello”附近使用的正确语法这是MySQL的解析器和预处理模块。这一步主要是根据SQL语法对语句进行词法语法分析和语义分析。词法分析词法分析是将一个完整的SQL语句分解成单个的单词。例如一条简单的SQL语句:selectnamefromuserwhereid=1andage>20;它会识别select,这是一个查询语句,然后识别用户,你要在这个表中做一个查询,然后识别where后面的条件,所以我需要找到这些内容。语法分析语法分析会对SQL做一些语法检查,比如单引号是否闭合,然后根据MySQL定义的语法规则,根据SQL语句生成一个数据结构。我们称这种数据结构为解析树(select_lex)。比如英语中的语法“Iuseis,youuseare”,如果错了,那是绝对不允许的。经过语法分析,发现你的SQL语句不符合规则,你会收到YouhavaanerrorinyourSQLsyntax错误信息。如果预处理器写了一条句法语法正确的SQL,但是表名或者字段不存在,会在哪里报错呢?是在数据库的执行层还是解析器?例如:从你好中选择*;解析的时候还是报错,SQL的解析有预处理器。它检查生成的解析树,解析解析器无法解析的语义。例如,它检查表名和列名是否存在,检查名称和别名,并确保没有歧义。预处理后得到一棵新的解析树。查询优化器是否只有一种SQL语句的执行模式?还是数据库最终执行的SQL和我们发送的SQL是一样的?答案是否定的。一条SQL语句可以有多种执行方式,最后返回相同的结果,它们是等价的。但是如果有这么多执行方法,那么这些执行方法是怎么得到的呢?最终选择哪一个?根据什么标准来选择?这就是MySQL的查询优化器模块(Optimizer)。查询优化器的目的是根据解析树生成不同的执行计划(ExecutionPlan),然后选择一个最优的执行计划。MySQL使用基于成本的优化器,开销最小。随便用。您可以使用此命令查看查询成本:showstatuslike'Last_query_cost';MySQL优化器可以处理哪些优化类型?举两个简单的例子:1、当我们对多个表进行关联查询时,以哪个表的数据作为参考表。2.当有多个索引可用时,选择哪个索引。事实上,对于每一个数据库来说,优化器模块都是必不可少的,它们使用复杂的算法来尽可能地达到优化查询效率的目的。但是优化器不是万能的,即使是垃圾SQL语句也不能自动优化,也不能每次都选择最优的执行计划,大家在写SQL语句的时候要注意。执行计划优化器最终会将解析树变成执行计划(execution_plans),这是一个数据结构。当然这个执行计划不一定是最优的执行计划,因为MySQL可能不会覆盖所有的执行计划。我们如何查看MySQL的执行计划呢?比如多表关联查询时,应该先查询哪个表?执行查询时可能会用到哪些索引,实际用到了哪些索引?MySQL提供了执行计划的工具。我们可以通过在SQL语句前加上EXPLAIN来查看执行计划信息。EXPLAIN从id=1的用户中选择名称;storageengine介绍存储引擎,我们先问两个问题:1、从逻辑上讲,我们的数据放在什么地方,或者放在什么结构中?2、执行计划在哪里执行?谁来执行?存储引擎的基本介绍是在关系型数据库中,数据放在表Table中。我们可以把这张表理解为一个Excel电子表格。因此,我们的表在存储数据的同时,还需要对数据的存储结构进行组织。这个存储结构是由我们的存储引擎决定的,所以我们也可以把存储引擎称为表类型。MySQL中支持多种存储引擎,并且可以替换,所以称为插件式存储引擎。为什么要支持那么多存储引擎?一个还不够吗?在MySQL中,每个表都可以指定它的存储引擎,而不是一个数据库只能使用一个存储引擎。存储引擎以表为单位使用。此外,存储引擎可以在创建表后进行修改。如何选择存储引擎?如果对数据一致性要求高,需要事务支持,可以选择InnoDB。如果数据查询多,更新少,对查询性能要求比较高,可以选择MyISAM。如果需要临时表进行查询,可以选择Memory。如果所有的存储引擎都不能满足你的需求,而且技术能力足够,你可以按照官网内部手册,用C语言开发一个存储引擎。(https://dev.mysql.com/doc/int...)执行引擎谁使用执行计划来操作存储引擎?这就是执行引擎(executor),它使用存储引擎提供的相应API来完成操作。为什么我们修改了表的存储引擎,而操作方式却不需要改变呢?因为不同功能的存储引擎实现的API都是一样的。最后将数据返回给客户端,即使没有结果。栗子还是以上面的sql语句为例,再梳理一下整个sql的执行过程。从id=1且年龄>20的用户中选择名称;通过连接器查询当前执行者的角色是否有权限,并执行查询。有则继续往下走,没有则拒绝,同时报Accessdeniedforuser的错误信息;接下来就是查询缓存了,首先查看缓存中有没有,如果有,那么就不用往下看了,直接把结果返回给客户端即可;如果不在缓存中,则执行解析器和预处理模块。(MySQL8.0版本直接删除了querycache的全部功能。)语法解析器和预处理主要分析SQL语句的词法和语法是否正确。如果没有问题,就会进行下一步,来到查询优化器;查询优化器会对sql语句进行优化,看哪种方法最划算,执行哪条sql语句。上面的sql有两个优化方案:先查询userName表中id为1的用户,然后再查找年龄大于20的人。先查询user表中所有年龄大于20的人,然后找到id为1的那个。在优化器决定选择哪种解决方案后,执行引擎就会执行它。然后将结果返回给客户端。结语如果文章对你有帮助,还是希望你看完后动动你的小手指,点赞、关注、收藏。