一条sql查询语句是如何执行的
如图所示
select * from table where ID=1这条sql在数据库中如何执行
mysql的基本架构图
大体上Mysql可以分为Server层和存储引擎层两部分
存储引擎层负责数据的存取,其架构模式是插件式的,支持InniDB,MylSAM,Memory等多个存储引擎,它从Mysql 5.5.5版本开始成为了默认存储引擎。
在执行create table创建表的时候,如果不指定引擎类型 默认的是使用InnoDB.要切换不同的存储引擎可以用engine=Memory 这里不同的存储引擎表数据的存储结构也是不一样的
连接器
第一步你会先来连接到这个数据库上,这时候接待你的就是连接器 连接命令:
mysql -h$ip -P$port -u$user -p
ip+端口号+用户名+密码
这里密码可以跟在-p的后面 这里需要注意的是来连接生产服务器的时候一定不要跟在-p的后面
连接命令中的mysql是客户端工具,用来跟服务端建立连接。在完成经典的TCP握手后,连接器就要开始认证你的身份,这时候用的就是你输入的用户名和密码
- 如果用户名和密码不对,你就会收到一个”Access denied for user “的错误然后客户端结束执行
如果用户名和密码认证通过,连接器会到权限表里查出你拥有的权限
连接完成后,如果你没有后续动作,这个连接就处于空闲状态 可以用show processlist
其中的Command列显示为”sleep“的这一行就表示系统里面有一个空闲连接
客户端如果太长时间没动静,连接器就会自动断开连接。这是时间的参数是由wait_timeout控制的默认值是8
如果连接中断,客户端再次发送请求,就会收到一个错误的提醒:Lost connection
to Mysql server during query 这时候如果想继续,就需要重连,然后执行请求。
长连接:客户端持续有请求
短链接:每次执行完很少的几次就断开来连接
连接的过程通常是比较复杂的,建议尽量减少建立连接的动作,也就是尽量使用长连接
但是这里要注意一个问题 全部使用长连接之后内存会占用的非常快。
这是因为MySQL在执行过程中临时使用的内存是管理在连接对象里面的,这些资源会在连接断开的时候才会释放,所以长时间积累下来可能导致内存占用太大,被系统强行杀掉,从现象看就是Mysql重启了。
怎么解决这个问题呢?
1.定期断开长连接。使用一段时间,或者程序里面判断执行过一个占用内存的大查询后,断开连接,之后要查询,再重新连接。
2.如果使用的是5.7+以上的版本,可以在每次执行一个较大的操作后,通过执行
mysql_reset_connection来重新初始化资源。这个过程不需要重连和重新进行权限验证
但是会将连接恢复到刚刚创建的状态
查询缓存
连接创建完成后,你就可以执行select 语句了,执行逻辑就会来到第二步:查询缓存
MySQL拿到一个查询请求后,会先到查询缓存看看,之前是不是执行过这条语句。之前执行过的语句及其结果可能会以key-value的形势,被直接缓存在内存中。key是查询的语句,value是查询的结果,如果你的查询能够直接在这个缓存中找到key,那么这个value就会直接返回给客户端。
如果查询语句不在缓存中,就会继续后面的执行阶段,执行完成后,查询结果会被缓存到查询缓存中
不过 在大多数情况下建议不要使用缓存查询 因为缓存查询往往弊大于利。
查询缓存的失效非常频繁,只要对一个表进行更新,这个表上所有的查询缓存就会清空。对于更新压力大的数据库来说,查询缓存的命中率会非常的低。除非你的业务就是一张静态表,很长时间才更新一次,比如系统配置的表 那张表上的查询。
MySQL比较人人性化的是:提供了一种“按需使用”的方式可以将参数query_cache_type设置成demand,这样对于默认的SQL语句都不使用查询缓存,对于你想确定用的查询缓存的语句可以用SQL_CACHE显示指定
select SQL_CACHE * from table where ID=1
需要注意的是mysql8.0版本已经直接查询缓存整个删掉了,也就是8.0开始彻底没有这个功能了。
分析器
如果没有命中缓存,就要开始真正执行语句了。首先MySql需要知道你要做什么,因此要对SQL语句进行解析。
分词器先会做词法分析你输入的是由多个字符串可空格组成的一条sql语句,Mysql需要识别出里面的字符串分别是什么,代表什么。
MySQL从你输入的“select”这个关键字识别出来这是一个查询语句。它也要把字符串“table”识别成表名“table”把字符串ID识别成“”列ID“
做完这些识别以后就要做”语法分析“根据词法分析的结果,语法分析器会根据语法规则 判断你输入的SQL语句是否满足MySql语法
如果你的语句不对,你就会收到”You have an error in your SQL syntax“的错误提醒
elect * from table where ID=1
一般语法错误会提示第一个出现错误的位置,所以你要关注的是紧接”use near“的内容
优化器
经过了分析器,Mysql就知道你要做什么了,在开始执行之前还是要经过优化器处理的,优化器是表里面有多个索引的时决定使用哪个索引;或者在一个语句有多表关联的时候,决定各个表的连接顺序
执行器
MySQL通过分析器就知道要做什么了,通过优化器就知道该怎么做了,于是就进入执行器阶段,开始执行语句
开始执行的时候 会判断你对这张表table有没有查询权限,如果没有就返回权限错误
如果有权限就继续执行,打开表的时候,执行器会根据表的引擎定义,去使用这个引擎接口。
比如我们这个列子表table中 ID没有索引,那么执行器的执行流程是这样的
1.调用InnoDB引擎接口取这个表的第一行,判断ID得值是不是10,如果不是则跳过,如果是则将这行存到结果集中
2.调用引擎接口取”下一行“重复相同的逻辑判断,直到取到这个表的最后一行
3。执行器将上述遍历过程中所有满足条件的行组成记录集返回给客户端
到这里这个执行语句就完成了
对于有索引的表执行逻辑也是相同的
你会在数据库中的慢查询中日志中看到一个rows_examined字段,表示这个语句执行过程中扫描了多少行。这个值就是在执行器每次调用引擎获取行的时候累加的。
但是这里需要注意的是 有些场景下,执行器执行一次,在引擎中扫描了多行因此引擎扫描的行数跟rows_examined并不是完全相同的
还没有评论,来说两句吧...