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

        平常我们在使用数据库的时候,看到的只是输入一条语句,返回一个结果,却不知道这条语句在 MySQL 内部的执行 过程。这篇文章就是讲MySQL拆解一下,了解内部运行机制,加深对MySQL的理解。

        下面是MySQL的基本架构图:

        从图上可以看到,MySQL总体上分为两大部分:Server层、存储引擎层。

        Server层:连接器、查询缓存、分析器、优化器、执行器 等,所有内置函数(日期、事件、

数学和加密函数等)、所有跨存储引擎的功能(视图、存储过程、触发器等) 也都在这一层实现。

        存储引擎层:存储引擎主要负责数据的存储和提取,其架构是插件式的,MySQL支持 InnoDB、MyISAM、 Memory 等多个存储引擎。现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开 始成为了默认存储引擎。

连接器

要使用MySQL,首先得需要建立连接,而连接器就是负责处理客户端的连接请求的。

客户端想要建立连接可以使用如下命令:

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

连接命令中的 mysql 是客户端工具,用来跟服务端建立连接。在完成经典的 TCP 握手后, 连接器就要开始认证你的身份,这个时候用的就是你输入的用户名和密码。

如果用户名密码认证通过,连接器会到权限表里面查出你拥有的权限。之后,这个连接里 面的权限判断逻辑,都将依赖于此时读到的权限。 这就意味着,一个用户成功建立连接后,即使你用管理员账号对这个用户的权限做了修改, 也不会影响已经存在连接的权限。需要重新连接才可以使用新权限。

连接完成后,如果没有后续动作,连接讲处于空闲状态,可以通过show processlist命令查看,超过八小时都没有新操作,连接将会断开。

数据库连接分为长和短,长连接就是客户端的持续请求使用的是同一个连接,而短连接则断开次数频繁。数据库的连接操作是很耗时的,因此更加推荐长连接,但是长连接过多就会出现MySQL内存变大的现象,因为长连接会导致资源的积累,一直没关闭长连接还可能会导致MySQL的异常重启。

既然推荐使用长连接,那怎么解决长连接资源释放问题?

1、定期断开长连接

2、如果你用的是 MySQL 5.7 或更新版本,可以在每次执行一个比较大的操作后,通过执行 mysql_reset_connection 来重新初始化连接资源。

查询缓存

连接建立完成后,会先在缓存中查询是否有值,缓存是key-value格式。

虽然使用缓存有时候会提高效率,但是在大多数场景下,缓存显得很鸡肋,因此不建议使用缓存。

可以将参数 query_cache_type 设置 成 DEMAND,这样对于默认的 SQL 语句都不使用查询缓存。

注:MySQL8.0版本已经不存在缓存这个功能了

分析器

到这一步就是真正开始执行sql语句,这里会对sql语句进行解析。

分析器先会做“词法分析”。你输入的是由多个字符串和空格组成的一条 SQL 语句, MySQL 需要识别出里面的字符串分别是什么,代表什么。

MySQL 从你输入的"select"这个关键字识别出来,这是一个查询语句。它也要把字符 串“T”识别成“表名 T”,把字符串“ID”识别成“列 ID”。

然后在做“语法分析”,根据词法分析的结果,语法分析器会根据语法 规则,判断你输入的这个 SQL 语句是否满足 MySQL 语法。

优化器

优化器的作用就是在有多个索引的情况下,选择使用哪个索引,或者在一个语句有多表关联 (join)的时候,决定各个表的连接顺序。

预处理

在执行sql之前,还有一个预处理阶段,这一阶段主要做两件事情:

  • 检查 SQL 查询语句中的表或者字段是否存在;
  • 将 select * 中的 * 符号,扩展为表上的所有列;

执行器

MySQL 通过分析器知道了你要做什么,通过优化器知道了该怎么做,执行就开始执行语句。

执行器做的事情有:判断表有没有执行查询的权限、调用表所定义的引擎的接口。

执行器和存储引擎的交互过程有三种:

  • 主键索引查询
  • 全表扫描
  • 索引下推

这里就简单介绍一下这三种方法的查询流程

主键索引查询:

  • 存储引擎通过主键索引的 B+ 树结构定位到 id = xxx的第一条记录
  • 执行器从存储引擎读到记录后,接着判断记录是否符合查询条件,如果符合则发送给客户端,如果不符合则跳过该记录

全表扫描:

  • 存储引擎读取表中的一条记录(从第一条开始),返回给执行器
  • 执行器判断条件符合就直接发送给客户端
  • 继续上述流程

索引下推:

        索引下推能够减少二级索引在查询时的回表操作,例如有如下sql:

select * from t_user  where age > 20 and reward = 100000; 

age 和 reward 字段建立了联合索引(age,reward),假如没使用索引下推,将会在二级索引中查询所有age>20的记录的id,然后回表查询对应的值,最后返回给执行器然后在对reward条件进行判断。而使用索引下推后,reward的判断提前到了回表这个阶段,不符合reward就直接排除,提高了查询的效率。

  • 25
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值