MYSQL执行一条SELECT语句的具体流程

这篇具有很好参考价值的文章主要介绍了MYSQL执行一条SELECT语句的具体流程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

昨天CSDN突然抽风 我一个ctrl+z把整篇文章给撤掉了还不能复原 直接心态崩了不想写了 不过这部分果然还是很重要,还是写出来吧

流程图 

MYSQL执行一条SELECT语句的具体流程,mysql,数据库

这里面总共有两层结构Server层 储存引擎

  • Server 层负责建立连接、分析和执行 SQL。MySQL 大多数的核心功能模块都在这实现,主要包括连接器,查询缓存、解析器、预处理器、优化器、执行器等。另外,所有的内置函数(如日期、时间、数学和加密函数等)和所有跨存储引擎的功能(如存储过程、触发器、视图等。)都在 Server 层实现。
  • 存储引擎层负责数据的存储和提取。支持 InnoDB、MyISAM、Memory 等多个存储引擎,不同的存储引擎共用一个 Server 层。现在最常用的存储引擎是 InnoDB,从 MySQL 5.5 版本开始, InnoDB 成为了 MySQL 的默认存储引擎。我们常说的索引数据结构,就是由存储引擎层实现的,不同的存储引擎支持的索引类型也不相同,比如 InnoDB 支持索引类型是 B+树 ,且是默认使用,也就是说在数据表中创建的主键索引和二级索引默认使用的是 B+ 树索引。

第一步:连接器 

就是用户和MYSQL相连接的过程,会发生三次握手和四次挥手,因为连接是基于TCP协议进行传输的

# -h 指定 MySQL 服务得 IP 地址,如果是连接本地的 MySQL服务,可以不用这个参数;
# -u 指定用户名,管理员角色名为 root;
# -p 指定密码,如果命令行中不填写密码(为了密码安全,建议不要在命令行写密码),就需要在交互对话里面输入密码
mysql -h$ip -u$user -p

 如果 MySQL 服务正常运行,完成 TCP 连接的建立后,连接器就要开始验证你的用户名和密码,如果用户名或密码不对,就收到一个"Access denied for user"的错误,然后客户端程序结束执行。

如果用户密码都没有问题,连接器就会获取该用户的权限,然后保存起来,后续该用户在此连接里的任何操作,都会基于连接开始时读到的权限进行权限逻辑的判断。

所以,如果一个用户已经建立了连接,即使管理员中途修改了该用户的权限,也不会影响已经存在连接的权限。修改完成后,只有再新建的连接才会使用新的权限设置。

可以通过

 SHOW PROCESSLIST;

查看有多少用户连接了MYSQL

MYSQL执行一条SELECT语句的具体流程,mysql,数据库

比如上图的显示结果,共有两个用户名为 root 的用户连接了 MySQL 服务,其中 id 为 6 的用户的 Command 列的状态为 Sleep ,这意味着该用户连接完 MySQL 服务就没有再执行过任何命令,也就是说这是一个空闲的连接,并且空闲的时长是 736 秒( Time 列)。

空闲连接会一直占用着吗?

当然不是了,MySQL 定义了空闲连接的最大空闲时长,由 wait_timeout 参数控制的,默认值是 8 小时(28880秒),如果空闲连接超过了这个时间,连接器就会自动将它断开。

mysql> show variables like 'wait_timeout';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout  | 28800 |
+---------------+-------+
1 row in set (0.00 sec)

当然,我们自己也可以手动断开空闲的连接,使用的是 kill connection + id 的命令。

长链接和短连接的区别

短连接
连接 mysql 服务(TCP 三次握手)
执行sql
断开 mysql 服务(TCP 四次挥手)

// 长连接
连接 mysql 服务(TCP 三次握手)
执行sql
执行sql
执行sql
....
断开 mysql 服务(TCP 四次挥手)

所以就是短连接只有一条SQL语句 长连接有多条SQL语句

同样一个任务我们使用长连接要比使用短连接节省了多次连接和断开MYSQL的过程

但是长连接就一点缺点没有吗?非也

MySQL 在执行查询过程中临时使用内存管理连接对象,这些连接对象资源只有在连接断开时才会释放。如果长连接累计很多,将导致 MySQL 服务占用内存太大,有可能会被系统强制杀掉,这样会发生 MySQL 服务异常重启的现象。

那我们如何解决这种问题吗

断开连接不就完事了嘛

1.定期手动断开连接

2.客户端主动重置连接。MySQL 5.7 版本实现了 mysql_reset_connection() 函数的接口,注意这是接口函数不是命令,那么当客户端执行了一个很大的操作后,在代码里调用 mysql_reset_connection 函数来重置连接,达到释放内存的效果。这个过程不需要重连和重新做权限验证,但是会将连接恢复到刚刚创建完时的状态。

每次学XX底层原理的时候都感觉,底层运行在替我负重前行

第二步:查询缓存 

连接工作结束之后,客户端就可以向MYSQL发送SQL语句了 它首先会解析语句的第一个字段 查看这是一条什么语句 假如说发送的是一个SELECT语句 那么它就会去去查询缓存( Query Cache )里查找缓存数据,看看之前有没有执行过这一条命令,这个查询缓存是以 key-value 形式保存在内存中的,key 为 SQL 查询语句,value 为 SQL 语句查询的结果。

如果查询的语句命中查询缓存,那么就会直接返回 value 给客户端。如果查询的语句没有命中查询缓存中,那么就要往下继续执行,等执行完后,查询的结果就会被存入查询缓存中。

这么一看 这太牛了 这个查询缓存 这不就像dp数组一样可以大量优化运行了吗

其实不然 因为每次对这张表更新数据的时候 这张表的缓存就会被全部清除....啊 也就是说 如果是更新后的数据查不到 只能是未更新的查询过一次的数据 

?那我查它干啥 我直接把上一次的查询结果拿出来用多好

很好 MYSQL也是这么想的 所以MYSQL8.0直接把这个东西给删了

第三步:解析SQL

第一件事:词法分析,MYSQL会分析你这个SQL语句中的关键子 然后形成SQL语法树 这样方便后面模块获取 SQL 类型、表名、字段名、 where 条件等等。 (给MYSQL来一把长难句分析)

第二件事:句法分析 就是看有没有语法错误

这里加粗了语法错误 字段,表,数据不存在那不是语法错误哦

就像JVM中的元数据验证 字节码验证一样

第四步:执行 SQL

MYSQL执行一条SELECT语句的具体流程,mysql,数据库

对应图中的四块

  • prepare 阶段,也就是预处理阶段;
  • optimize 阶段,也就是优化阶段;
  • execute 阶段,也就是执行阶段;

预处理阶段 

 那肯定在预处理器中,于SELECT而言 预处理就做俩事

1.查看字段,表等数据是否存在

2.把* 替换成全部列

优化阶段

对应的当然是优化器

我们知道MYSQL执行语句的时候贼麻烦 又要判断这个索引又判断那个长度的 就是这一步 要确定一个执行的具体方案

我们可以在查询语句最前面加个 explain 命令,这样就会输出这条 SQL 语句的执行计划,然后执行计划中的 key 就表示执行过程中使用了哪个索引 若果这个key参数是null的话 就说明没有使用索引 也就是说 使用的是效率最差的全表查询

具体来讲 优化器会选择什么方案呢?

SELECT id FROM product WHERE id > 1  AND name LIKE 'i%';

这条查询语句的结果既可以使用主键索引,也可以使用普通索引,但是执行的效率会不同。这时,就需要优化器来决定使用哪个索引了。

这里使用的是覆盖索引,也就是说 同时使用这两个索引 这两个索引上的信息足够满足查询请求,不需要再回到主键索引上去取数据。(查询主键索引的 B+ 树的成本会比查询二级索引的 B+ 的成本大,优化器基于查询成本的考虑,会选择查询代价小的普通索引。)

就是个啥流程呢 首先先在二级索引(name)中 找到匹配的数据 然后二级索引存的数据就是主键id 然后记录id>1的数据 所以就不用再去主键索引了 直接就出结果了

执行阶段 

执行阶段 那肯定是执行器

经历过优化器了 我们已经得到了执行方案 那现在就是正式的执行SQL的时机了

执行的过程中,执行器就会和存储引擎交互了,交互是以记录为单位的。

拢共有三种执行方式:

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

主键索引查询

从语文的角度分析 他肯定是通过主键索引查询的对吧(?)

我们看这行代码

select * from product where id = 1;

 首先id为主键 肯定为1 再有这个筛选条件是等值 所以一定只会查询一次

执行器第一次查询 调用read_first_record 函数指针指向的函数

这个函数指针被指向为 InnoDB 引擎索引查询的接口(优化器参数为const 有这个参数 储存引擎才能选择对应的执行方式),把条件 id = 1 交给存储引擎,让存储引擎定位符合条件的第一条记录。然后呢储存引擎通过主键索引(b+树)找到id为1的数据

判断1:如果记录是不存在的,就会向执行器上报记录找不到的错误,然后查询结束。如果记录是存在的,就会将记录返回给执行器;

然后如果存在的话 判断2

查看是否符合筛选条件 如果符合发送给客户端,如果不符合则跳过该记录。

执行器查询的过程是一个 while 循环,所以还会再查一次,但是这次因为不是第一次查询了,所以这次会调用 read_record 函数指针指向的函数(区别于上面的read_first_record),因为优化器选择的访问类型为 const(前面提到的这个参数再次出现),这个函数指针被指向为一个永远返回 - 1 的函数,所以当调用该函数的时候,执行器就退出循环,也就是结束查询了

全表扫描

select * from product where name = 'iphone';

第一步不变 还是调用 read_first_record 函数指针指向的函数 但是这次因为是全表扫描(优化器参数为all)

第二步 从第一条记录开始读取,看它是否满足WHERE条件(name = iPhone) 如果不满足跳过,满足把这条记录发给客户端

执行器查询的过程是一个 while 循环,所以还会再查一次,会调用 read_record 函数指针指向的函数,因为优化器选择的访问类型为 all,read_record 函数指针指向的还是 InnoDB 引擎全扫描的接口,所以接着向存储引擎层要求继续读刚才那条记录的下一条记录,存储引擎把下一条记录取出后就将其返回给执行器(Server层),执行器继续判断条件,不符合查询条件即跳过该记录,否则发送到客户端;一直重复上述过程,直到存储引擎把表中的所有记录读完,然后向执行器(Server层) 返回了读取完毕的信息; 执行器收到存储引擎报告的查询完毕的信息,退出循环,停止查询。 

索引下推

它是MySQL 5.6 推出的查询优化策略

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

假如说我们创建了 对于age和reward的索引

联合索引当遇到范围查询 (>、<) 就会停止匹配,也就是 age 字段能用到联合索引,但是 reward 字段则无法利用到索引(硬记就行 后面可能会更新索引失效的部分)

如果不使用索引下推

第一步还是: server层调用储存引擎 找到满足age>20的第一条记录

第二步:存储引擎根据二级索引的 B+ 树快速定位到这条记录后,获取主键值,然后进行回表操作,将完整的记录返回给 Server 层

第三步:

server再判断reward是否等于100000 如果符合 返回给用户 不符合忽略

第四步:接着拿下一条记录(不需要再次定位记录了 记录之间由链表连接) 存储引擎在二级索引定位到记录后,获取主键值,然后回表操作拿到全部记录数据 判断是否符合

然后三四步循环 直到age>20的记录查询完毕

没有索引下推的时候,每查询到一条二级索引记录,都要进行回表操作,然后将记录返回给 Server,接着 Server 再判断该记录的 reward 是否等于 100000

那么有索引下推的时候呢?

Server 层首先调用存储引擎的接口定位到满足查询条件的第一条二级索引记录,也就是定位到 age > 20 的第一条记录;

存储引擎定位到二级索引后,先不执行回表操作,而是先判断一下该索引中包含的列(reward列)的条件(reward 是否等于 100000)是否成立。如果条件不成立,则直接跳过该二级索引。如果成立,则执行回表操作,将完成记录返回给 Server 层。

Server 层在判断其他的查询条件(本次查询没有其他条件)是否成立(为什么只有reward条件可以用储存引擎判断呢? 因为它虽然没用上联合索引 但是索引的数据还是有的 在联合索引中对着id找reward还是很方便的(一对一对应的)),如果成立则将其发送给客户端;否则跳过该记录,然后向存储引擎索要下一条记录。 如此往复,直到存储引擎把表中的所有记录读完。

就相当于把判断reward是否等于100000这件事外包给储存引擎了

索引下推能够减少二级索引在查询时的回表操作,提高查询的效率,因为它将 Server 层部分负责的事情,交给存储引擎层去处理了文章来源地址https://www.toymoban.com/news/detail-521910.html

到了这里,关于MYSQL执行一条SELECT语句的具体流程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • MySQL面试题:一条SQL语句在MySQL中执行过程全解析

    介绍一下下图涉及的一些组件的基本作用帮助大家理解这幅图。 连接/线程处理(连接器): 身份认证和权限相关(如连接处理、授权认证、安全等等)。 查询缓存: 执行查询语句的时候,会先查询缓存(MySQL 8.0 版本后移除)。 解析器: 没有命中缓存的话,SQL 语句就会经过解析

    2024年02月03日
    浏览(31)
  • MySQL Select 语句执行顺序

    一条 SQL 查询语句结构如下: 但真正的执行步骤如下,执行时,每个步骤都会产生一个虚拟表,该虚拟表被用作下一个步骤的输入: 1. FROM 在这一步,无论后面跟那种联接运算(LEFT JOIN、RIGHT JOIN等),都首先执行交叉联接(CROSS JOIN),计算笛卡尔积,生成虚拟表 VT-1 2. ON 根

    2024年02月05日
    浏览(32)
  • 【MySQL系列】- SELECT语句执行顺序

    2.1 执行FROM操作 这一步需要做的是对FROM子句前后的两张表进行笛卡尔积操作,也称作为交叉连接,生成虚拟表VT1。如果FROM子句前的表包含a行数据,FROM子句后的表中包含b行数据,那么虚拟表VT1将包含a*b行数据。 2.2 应用ON过滤器 SELECT查询共有3个过滤流程,分别是ON、WHERE、

    2024年02月08日
    浏览(35)
  • Mysql的学习与巩固:一条SQL查询语句是如何执行的?

    我们经常说,看一个事儿千万不要直接陷入细节里,你应该先鸟瞰其全貌,这样能够帮助你从高维度理解问题。同样,对于MySQL的学习也是这样。平时我们使用数据库,看到的通常都是一个整体。比如,你有个最简单的表,表里只有一个ID字段,在执行下面这个查询语句时:

    2023年04月13日
    浏览(68)
  • MYSQL实战45讲笔记--基础架构:一条SQL查询语句是如何执行的?

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

    2024年02月07日
    浏览(33)
  • MySQL数据库——MySQL SELECT:数据表查询语句

    在 MySQL 中,可以使用 SELECT 语句来查询数据。查询数据是指从数据库中根据需求,使用不同的查询方式来获取不同的数据,是使用频率最高、最重要的操作。 SELECT 的语法格式如下: 其中,各条子句的含义如下: {*|字段列名} 包含星号通配符的字段列表,表示所要查询字段的

    2024年02月05日
    浏览(38)
  • MySQL中,SQL 查询总是先执行SELECT语句吗?

    在使用 MySQL 进行查询时,我们通常会使用 SELECT 语句,但是 SELECT 语句是否总是最先被执行呢?这是一个非常有趣的问题,本文将对此进行探讨。 在 MySQL 中,SQL 查询通常包括以下几个步骤: 语法解析 :MySQL 会对 SQL 查询语句进行语法解析,检查语句是否符合 SQL 语法规范。

    2023年04月09日
    浏览(33)
  • 基本的SELECT语句——“MySQL数据库”

    各位CSDN的uu们好呀,好久没有更新小雅兰的MySQL数据库专栏啦,接下来一段时间,小雅兰都会更新MySQL数据库的知识,下面,让我们进入今天的主题吧——基本的SELECT语句!!! SQL概述 SQL语言的规则与规范 基本的SELECT语句 显示表结构 过滤数据 1946 年,世界上第一台电脑诞生

    2024年02月09日
    浏览(37)
  • Mysql数据库:select from语句详解

    💖The Begin💖点点关注,收藏不迷路💖 select from语句用于从数据库中查询数据。它由两个组成:select 和from。 select 用于指定要查询的列,from用于指定要查询的表。 通过结合使用这两个,我们可以从数据库中选择特定的列和行进行查询。 下面是se

    2024年02月03日
    浏览(28)
  • Mysql数据库(六):基本的SELECT语句

    本博主将用CSDN记录软件开发求学之路上亲身所得与所学的心得与知识,有兴趣的小伙伴可以关注博主!也许一个人独行,可以走的很快,但是一群人结伴而行,才能走的更远! 语法: 选择全部列: 一般情况下,除非需要使用表中所有的字段数据,最好不要使用通配符‘ *

    2024年02月08日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包