一条SQL语句是如何执行的?--Mysql45讲笔记记录 打卡day1
写在前面的话:回想以前上班的时候,空闲时间还是挺多的,但是都荒废了。如今找工作着实费劲了。但是这段时间在极客时间买了mysql45讲,就好像发现了新大陆一样,这是我认真做笔记的第一天,说实话第一讲我已经看了有5遍了吧。今晚认真读了一遍也思考了一遍,打算做一下记录,也让自己再回想一遍,加深印象。其实第一次读也就读到第八讲,然后去面试的时候好多问题都跟这个课程的有关,还好也回答上来了,但感觉不是很深入回答的。现在也想明白了,学习知识这种事情不能操之过急,越着急越静不下心来。给自己定一个目标,从今天开始2天记录一篇mysql45讲的博客。为了督促自己吧。这一晃几个月又过去了,如果几个月前就坚持了,那90天都已经读完了。加油你肯定行的。那就开始吧。
如果我们有一条简单的sql语句是下面这样的
SELECT * FROM T WHERE ID = 10;
按照之前我们可能只知道这条语句最终的执行结果是什么,但是从来没有想过它内部是怎么执行的,所以有时候当出现了问题,也云里雾里的。下面就来说一下它的内部执行过程。
mysql分为server层和存储引擎层
server层包括连接器,查询缓存,分析器,优化器,执行器,涵盖了mysql的大多数核心服务功能,以及所有的内置函数(如日期,时间,数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程,触发器,视图等。
存储引擎层负责数据的存储和提取。架构模式是插件式的,支持innodb,myisam,memory等多个存储引擎。现在常用的是innodb,mysql5.5.5版本开始innodb成为了默认存储引擎
然后开始说执行顺序
第一步,我们会先连接到数据库,这个时候接待你的就是连接器,连接器负责跟客户端简历连接,获取权限,维持和管理连接。连接命令一般是这样写的
mysq -h$ip -p$port -u$user -p
连接命令中的mysql是客户端工具,用来跟服务端建立连接。在完成TCP握手后,连接器就要开始认真我们的身份,这个时候用的就是我们输入的用户名和密码
如果用户名或者密码不对,就会提示“access denied for user"的错误,然后客户端程序结束执行。
如果用户名密码认证通过,连接器会到权限表里面查出我们拥有的权限。也就是说这个连接里的权限判断逻辑,都依赖这个时候从权限表里读到的权限。
这就意味着,一个用户成功连接后,即使你用管理员账号对这个用户对权限做了修改,也不会影响已经存在连接的权限。修改完后,只有再新建的连接才会使用此次新的权限设置。
连接完成后,如果没有后续的动作,这个连接就会处于空闲状态。通过show processlist 可以看到 其中command列为sleep的这一行,就表示现在系统里面有一个空闲连接。客户端如果太长时间没有动静,连接器就会自动断开。有个参数wait_timeout可以控制,默认值为8小时。如果在连接被断开后,客户端再次发送请求的话,就会收到一个错误提醒,这个时候就需要重新连接,再执行请求。
第二步,连接建立成功后,就可以执行select语句了。查询缓存。
mysql拿到一个查询请求后,会先到查询缓存看,之前是不是执行过这条语句,如果之前执行过就会从缓存中读取。缓存中的语句以及结果会以key-value的形式,被缓存在内存中。key是查询语句,value是查询结果。
如果语句不存在缓存中,就会继续执行后面的执行阶段。执行完成后,执行结果会被存入到查询缓存中。如果查询命中缓存,mysql不需要执行后面的复杂操作,就可以直接返回结果。这个效率会很高。但是大多数情况下不建议使用查询缓存,因为查询缓存的失效非常频繁,只要有一个表的更新,这个标上所有的查询都会被情况。因此可能你费劲把记过存起来了,还没使用就被一个更新全清空了。对于更新比较频繁的数据库来说,查询缓存的命中率会非常弟。更适合与那种不经常被修改的表,很长时间才会更新一次,比如系统配置表。
mysql也提供了这种按需使用的方式,可以将参数query_cache_type设置成demand。这样对于默认的sql语句都不使用查询缓存。而对于你确定要使用查询缓存的语句,可以用sql_cache显示来制定
select SQL_CACHE * FROM T WHERE ID = 10;
需要注意的是mysql8.0直接将查询缓存整块功能删除了
第三步,如果没有命中查询缓存,就要开始真正执行语句了。也就是开始执行分析器。
首先,mysql需要知道你要做什么,因此需要对sql语句做解析。分析器会做词法分析。我们输入的是由多个字符串和空格组成的一条sql语句,mysql需要识别出里面的字符串分别是什么,代表什么。
mysql从select这个关键字识别出来,这是一个查询语句。它也要把字符串t识别成表名t,把字符串id识别成列id.
做完了这些识别后,就要做语法分析,根据词法分析的结果,语法分析器会根据语法规则,判断输入的这个sql语句是否满足mysql语法。如果语句不对就会收到“you have error in your sql syntax"的错误停下,比如select 少打了开头的字母s.也会报这个错。
第四步,优化器。经过了分析器mysql就知道你要做什么了。在开始之前 还要经过优化器的处理。
优化器在表里有多个索引的时候,决定使用哪个索引,或者在一个语句有多表关联的时候,决定各个表的顺序。优化器阶段完成后 这个语句执行的方案就确定下来了。然后进入执行器阶段
第五步,mysql通过分析器知道了你要做什么,通过优化器知道了该怎么做,于是就进入了执行期阶段,开始执行语句。
开始执行的时候,要先判断一下你对这个表有没有执行查询的权限,如果没有,就会返回没有权限的错误。如果有权限就会打开表继续执行,打开表的时候 执行期就会根据表的引擎定义,去使用这个引擎提供的接口。
比如这个例子中的表t id字段没有索引,那么执行期的执行流程就是这样的:
1.调用innodb引擎接口取遍的第一行,判断id值是不是10,如果不是则跳过,如果是就将这行存在结果集中
2.调用引擎接口取下一行,重复相同的判断逻辑,直到渠道这个表的最后一行。
3.执行期将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回客户端。
这个语句就执行完成了
对于有索引的表执行逻辑也是一样的
数据库的慢查询日志中有一个rows_examined的字段,表示这个语句执行过程中扫描了多少行。这个值就是在执行期每次调用引擎获取数据行的时候累加的。
在有些场景下 执行期调用一次 引擎内部会扫描多行 因此引擎扫描行数跟rows_examined并不是完全相同的。
后记
写第一讲大概写了1个小时,刚开始大部分都是按照原文来写的,写着看着突然也就觉得玲琅满目了,发现之前看的只是了解的一部分,写一遍才发现有那么多知识点是之前没有注意到的。
需要了解的知识点:
1.慢查询日志
就先到这里把。晚安。坚持。