您的位置:首页 > 数据库

一条SQL查询语句是如何执行的?-笔记

2019-01-09 23:40 681 查看

MySQL基本架构示意图如下,从图中我们可以清楚地看到SQL语句在MySQL的各个功能模块中的执行过程
MySQL可分为Server层存储引擎层两部分。

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

存储引擎负责数据的存储提取。其架构模式是插件式的,支持InnoDB,它从MySQL5.5.5版本开始成为了默认存储引擎。
图中可以看到不同存储引擎共用一个Server层。

连接器

首先,我们连接到这个数据库上,这时接待你的就是连接器,连接器负责与客户端建立连接、获取权限、维持和管理连接。连接命令如下:

$ mysq -uroot -p

密码可直接跟在-p后面写在命令行中,但是这样可能会导致你的密码泄露。因此输完命令后我们最好在交互对话里面输入密码

连接命令中的mysql是客户端工具,用来跟服务器建立连接,在完成经典的TCP握手后,连接器就要开始认证你的身份。用户名和密码认证通过后,连接器会到权限表里面查出你拥有的权限。之后这个连接里的权限判断逻辑都将依赖于此时读到的权限。这意味着,用户连接成功后,即使管理员账号对这个用户的权限做了修改,也不会影响已存在连接的权限,只有新建的连接才会使用新的权限设置。链接完成后若没有后续的动作,这个连接就处于空闲状态,你可以在show processlist命令中看到它。若客户端太长时间没有动静,连接器就会自动将它断开。这个时间由参数wait_timeout控制,默认值8h

数据库中长连接是指连接成功后,如果客户端持续有请求,则一直使用一个连接。短连接则是指每次执行完很少的几次查询就断开连接,下次查询新建。使用中尽量减少建立连接的动作,即多使用长连接。

但全使用长连接会使MySQL占用内存涨的特别快,若长期下来可能导致内存占用太大,被系统强行杀掉(OOM),从现象来看就是MySQL重启。如何解决这个问题?

  • 定期断开长连接
  • 若使用的MySQL5.7以上新版本,可在每次执行一个比较大的操作后通过执行mysql_reset_connection来重新初始化连接资源。

查询缓存

MySQL拿到一个查询请求后会先到查询缓存看看,之前是不是执行过这条语句。之前执行的语句及其结果会以key-value对的形式被直接缓存在内存中。若查询能在缓存中找到key,那么这个value会被直接返回给客户端。若不在查询缓存中,会继续后面的执行阶段,执行完毕将结果存入查询缓存中。
若查询命中缓存,MySQL不需要执行后面的复杂操作就可以直接返回结果,这个效率会很高。

但查询缓存弊大于利!!

只要对表更新,这个表上所有的查询缓存都会被清空。若数据库经常更新,那么查询缓存的命中率会非常低。若是一张很长时间才会更新一次的静态表才适合使用查询缓存。

将参数query_cache_type设置成DEMAND,这样对于默认的SQL语句都不使用查询缓存,需要查询缓存的语句,使用SQL_CACHE显示指定,例如:

mysql> select SQL_CACHE * from T where ID=10;

注意!!!MySQL8.0版本中直接将查询缓存删了,即彻底没有这个功能了。

分析器

这里开始真正执行语句了。MySQL对语句做解析。分析器先做“词法分析”,再做“语法分析”。这个阶段就可以分析出表中是否存在对应的字段,比如

select * from T where k=1
,k列不存在就会报错。

优化器

当表中有多个索引的时候,决定使用哪个索引或在一个语句中有多表关联的时候,决定各个表的连接顺序,不同的顺序会有不同的执行效率。

执行器

开始执行时要先判断你对这个表有没有执行查询的权限,有权限就继续打开表执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。

执行顺序是“第一次调用取满足条件的第一行这个接口”然后“循环取满足条件的下一行这个接口”,这些接口都是引擎中已经定义好的。数据库慢查询日志中会看到一个rows_examined字段,这个值是在执行器每次调用引擎获取数据行的时候累加的,但某些情况下执行器调用一次,在引擎内部扫描多行,因此引擎扫描函数与rows_examined不完全相同

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: