一文带你读懂一条sql的执行过程

一条sql的执行过程
mysql> select * from T where ID=10

在这里插入图片描述

大体来说,mysql大致分为Server层,引擎层

  • Server层包括 连接器,分析器,优化器,执行器,查询缓存等,涵盖MySQL的大多数核心服务功能,以及所有的内置函数(时间,日期,数学,加解密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程,触发器,视图等

  • 而存储引擎则负责数据的存储,提供读写接口。支持InnoDB,MyISAM,Memory等多个存储引擎

如果你指定引擎类型,在创建表的时候默认使用InnoDB.
不同的存储引擎共用一个Server层

连接器

第一步,你会先连接到数据库上,这时候接待你的就是连接器,连接器负责跟客户端简历连接,获取权限,维持和管理连接。连接命令如下:

mysql -h$ip -P$port -u$user -p

输入完命令之后,需要在交互里面输入密码,虽然密码可以跟在 -p 的后面,但是强烈不建议这样做,可能会导致你的密码泄露。如果你连的是生成数据库,更加不能这样做。

连接命令中的MySQL是客户端工具,用来跟服务端建立连接。在完成经典的TCP握手之后,连接器就开始确认你的身份。

如果用户密码不对,会收到一个“Access denied for user" 的错误,
如果用户名密码认证通过,连接器会到权限表里面查出你拥有的权限。

连接完成之后,如果你后续没有动作,这个连接就处于空闲状态,你可以在show processlist 命令中看到它。其中的Command列显示为"Sleep”者一行,就表示系统里面有一个空闲连接
在这里插入图片描述

如果连接器被断开之后,客户端再次请求的时候,会收到一个错误提醒,Lost connection to Mysql server during query .
如果客户端长时间没有动静,连接器会自动将他断开。默认是8小时。
数据库中存在短链接和长连接,由于建立连接的过程是比较复杂,所以建议尽量都使用长连接,但是过多的长连接又会导致Mysql的内存涨的特别快,因为MySQL在执行过程中临时使用的内存是管理子啊连接管理对象上,这些资源会在断开的时候菜释放,所以所过长连接积累下来,导致内存占用过大,导致OOM,MySQL服务重启。
在这里插入图片描述

解决方案:

  • 1,定期断开长连接,使用一段时间,或者程序里面判断执行过一个占用内存的大查询后,断开连接,之后查询要重连。
  • 2,MySQL或者更新版本,可以在每次执行一个比较大的操作后,通过执行MySQL_reset_connection来重新初始化连接资源。

查询缓存

建立完连接后,执行select语句
MySQL拿到一个查询请求后,会先查询缓存看看,缓存可能会以key-value的形式,key是查出语句,value是结果。
如果语句不在查询缓存中,则执行后面的语句,如果命中缓存,则直接返回结果。
但是大部分情况下不建议查询缓存,因为只要有一个对表的更新,这个表上的所有缓存都会被清空。
不过MySQL也提供了按需使用,可以将参数query_cache_type设置成DEMAND,这样设置默认查询不使用缓存。而如果要用的话可以用SQL_CACHE.

mysql> select SQL_CACHE * from T where ID=10

分析器

如果没有查询出缓存,就开始执行语句。
分析器会做词法分析,你输入的是由多个字符串和空格组成的一条sql语句,需要找出里面的字符串分别是什么,代表什么

mysql> elect * from t where ID=1;

ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'elect * from t where ID=1' at line 1

这边select故意少写了一个s,mysql会有错误提示。一般语法错误提示第一个出现错误的位置,所以要关注的是紧挨“user near"的内容。
MySQL从你输入的select判断这是一个查询语句,要把T识别成一张表,要把ID识别成列ID

优化器

经过了分析器,MySQL就知道你要做什么,在执行开始之前,还要进行优化处理。
优化器是在表里面有多个索引的时候,决定使用哪个索引,或者在一个语句中有多表关联jion的时候,决定各个表的连接顺序。

mysql> select * from t1 join t2 using(ID)  where t1.c=10 and t2.d=20;

可以从t1表里面找到c等于10的id值,在根据id值关联到t2,在判断t2里面的d的值等于20的
相反也可以根据t2等于20的id值,根据di值关联到t1,判断t1里面的c值等于10的
这两种执行结果是一致的,但是执行的效率却是不同的,而优化器的作用就是决定使用哪一个方案。

执行器

MySQL通过分析器知道了你要做什么,通过优化器知道了怎么做,然后就进入到执行器
开始执行的时候,会判断一下你对T表有没有执行的权限,如果没有,则返回没有权限的错误,如果命中缓存,则直接返回结果,

mysql> select * from T where ID=10;

ERROR 1142 (42000): SELECT command denied to user 'b'@'localhost' for table 'T'

如果有权限,就打开表继续执行,打开表的时候,执行器会根据表的引擎定义,去使用这个引擎提供共的接口
比如表T,ID字段没有索引,那么执行器的流程如下:

  • 1,调用InnoDB引擎接口取这个表的第一行,判断ID是不是等于10 ,如果不是则跳过,如果是则将这行存在结果集里面
  • 2。调用引擎接口取”下一行“重复相同的判断逻辑,直到取到这个表的最后一行。
    3.执行器将上述遍历过程中所有满足条件组成的记录作为结果集返回给客户端。

对于有索引的表执行的逻辑也差不多,第一次调用都是”取满足条件的第一行“这个接口,之后循环取”满足条件的下一行“

可以在数据库慢查询日志中看到一个rows_examined字段,表示这个语句执行过程扫描了多少行。

这边抛出一个问题

select * from ahhh where ID=10;

如果数据库里面没有表ahhh的话,大家觉得会是在哪一个阶段发现错误的呢。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值