【MySQL | 第11篇】一条SQL查询语句的执行全流程简析

文章目录

    • [0. MySQL 的宏观架构:概览](#0. MySQL 的宏观架构:概览)
    • [1. 第一步:连接器------建立连接](#1. 第一步:连接器——建立连接)
    • [2. 第二步:查询缓存------历史功能](#2. 第二步:查询缓存——历史功能)
    • [3. 第三步:解析器------语法解析](#3. 第三步:解析器——语法解析)
    • [4. 第四步:优化器------查询优化](#4. 第四步:优化器——查询优化)
    • [5. 第五步:执行器------查询执行](#5. 第五步:执行器——查询执行)
    • [6. 第六步:存储引擎------数据存储](#6. 第六步:存储引擎——数据存储)
    • 总结:完整流程

一条简单的 SQL语句 SELECT * FROM user WHERE id = 1;

当按下回车键的那一刻,MySQL 内部究竟发生了什么?它是如何找到数据的?为什么有时候加了索引还是慢?

这篇笔记,从连接、缓存、解析、优化、执行存储引擎,全流程还原一条查询语句的流程。


0. MySQL 的宏观架构:概览

在深入细节之前,需要先了解 MySQL 的基础架构图。MySQL 可以大致分为两层:

  1. Server 层(大脑):涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等)。所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。
  2. 存储引擎层(手脚) :负责数据的存储和提取。其架构模式是插件式的,支持 InnoDB、MyISAM、Memory 等多个存储引擎。目前最常用的默认引擎是 InnoDB

核心流程概览:

连接器 → \rightarrow → 查询缓存(MySQL 8.0前) → \rightarrow → 分析器 → \rightarrow → 优化器 → \rightarrow → 执行器 → \rightarrow → 存储引擎


1. 第一步:连接器------建立连接

执行 SQL 时,第一件事是连接到数据库。

  • 职责:负责与客户端建立连接、获取权限、维持和管理连接。
  • 交互流程
    1. TCP 握手:基于 TCP/IP 协议建立物理连接。
    2. 身份认证:验证用户名和密码。
    3. 权限获取 :一旦认证通过,连接器会到权限表中查询对应的权限。需要注意的是,连接建立后,即使管理员修改了权限,在当前连接断开前也不会生效。
  • 长连接与短连接
    • 通常建议使用长连接以减少握手开销。
    • 潜在问题:MySQL 在执行过程中临时使用的内存由连接对象管理。长连接累积会导致内存占用过大,可能被系统强行终止(OOM)。
    • 解决方案:定期断开长连接或初始化连接资源。

2. 第二步:查询缓存------历史功能

注意:此功能主要存在于 MySQL 8.0 之前。MySQL 8.0 版本已正式删除了查询缓存。

  • 逻辑 :连接建立后,MySQL 会先查询缓存。如果之前执行过相同的语句,结果会以 Key-Value 的形式直接缓存在内存中(Key 是 SQL 语句,Value 是查询结果)。
  • 命中:如果命中,直接返回结果,速度极快。
  • 弊端(被废弃的原因)
    • 失效频繁 :只要对一个表进行更新操作(Insert/Update/Delete),该表上所有的查询缓存都会被清空。对于更新频繁的数据库,缓存几乎无用且增加了额外开销。
    • 适用场景有限:仅对静态数据表有效。

3. 第三步:解析器------语法解析

如果没有命中缓存,或者缓存功能不存在,SQL 就真正开始进入执行流程。首先要解决的问题是:解析 SQL 语句的意图。

这一步分为两个阶段:

SQL语句可以算是一种编程语言(结构化S 查询Q 语言L ),所以一般编译器具有的功能,SQL的解析器也需要具备

  1. 词法分析

    • 将输入的 SQL 文本字符串,识别出各个组成部分及其含义。
    • 例如:将 SELECT 识别为查询关键字 ,将 user 识别为表名,将 id 识别为列名。
  2. 语法分析

    • 根据词法分析的结果,判断 SQL 语句是否满足 MySQL 的语法规则。
    • 错误产生 :常见的语法错误提示 You have an error in your SQL syntax 就是在此阶段产生。

预处理器

在某些架构划分中,分析器之后还存在一个预处理阶段,用于检查表名、列名是否存在,消除字段歧义,并进行权限验证。


4. 第四步:优化器------查询优化

经过分析器,MySQL 明确了要执行的操作。但在开始执行之前,需要经过优化器的处理。这是影响 MySQL 性能的关键环节。

  • 职责:决定使用哪个索引,或者在多表关联时,决定各个表的连接顺序。

  • 例如

    sql 复制代码
    SELECT * FROM t1 JOIN t2 USING(ID) WHERE t1.c = 10 AND t2.d = 20;
    • 方案 A:先从 t1 查出 c=10 的记录,通过 ID 关联到 t2,再判断 t2.d=20。
    • 方案 B:先从 t2 查出 d=20 的记录,通过 ID 关联到 t1,再判断 t1.c=10。
    • 优化器的作用:通过基于成本的评估,选择执行效率最高的方案。
  • 产出 :生成执行计划

    基于 explain 关键字,可以查询 SQL执行计划


5. 第五步:执行器------查询执行

优化器选定方案后,将任务交给执行器。

  1. 权限复核:执行器在执行前会再次确认对相关表是否具有查询权限(如果在预处理阶段未检查)。
  2. 调用引擎接口 :执行器本身不存储数据,通过调用存储引擎提供的 API 接口来获取数据。

SELECT * FROM user WHERE id = 1; 为例(假设 id 字段没有索引):

  1. 调用 InnoDB 引擎接口取该表的第一行
  2. 判断 ID 是否为 1,如果不是则跳过,如果是则将该行存入结果集。
  3. 调用引擎接口取下一行
  4. 重复相同的判断逻辑,直到取到表的最后一行。
  5. 执行器将所有满足条件的记录组成结果集,返回给客户端。

说明 :在数据库慢查询日志中看到的 rows_examined(扫描行数),就是在执行器每次调用引擎获取数据行时累加的。


6. 第六步:存储引擎------数据存储

这是数据的最终存储层。执行器调用的 API 最终由存储引擎实现。

  • InnoDB(默认)
    • 数据按聚簇索引(B+树)结构存储。
    • 如果查询使用索引,直接在 B+ 树上进行搜索,速度很快。
    • 如果不使用索引(全表扫描),InnoDB 需要将所有数据页加载到内存(Buffer Pool)中供执行器逐行判断。

总结:完整流程

回顾 SELECT * FROM user WHERE id = 1 的执行过程:

  1. 连接器:验证身份,分配连接线程。
  2. 查询缓存(MySQL 8.0前):检查是否有缓存结果,有则直接返回,无则继续。
  3. 分析器:识别语句为查询操作,检查语法正确性。
  4. 优化器 :发现 id 字段有索引,决定使用主键索引进行查询,生成执行计划。
  5. 执行器:调用 InnoDB 引擎的数据获取接口。
  6. InnoDB:在 B+ 树索引中定位到 id=1 的行,返回给执行器。
  7. 执行器:接收数据,返回给客户端。

总结:

了解SQL语句的执行流程,对于SQL 性能调优有一定的帮助,比如:

  • 明白优化器是基于成本进行选择,就能理解为何有时 MySQL 会选错索引
  • 了解执行器存储引擎的交互方式,就能知道全表扫描效率低下的原因
  • 等等
相关推荐
w***29852 小时前
Knife4j文档请求异常(基于SpringBoot3,查找原因并解决)
java·服务器·数据库
RFG201210 小时前
20、详解Dubbo框架:消费方如何动态获取服务提供方地址?【微服务架构入门】
java·人工智能·后端·微服务·云原生·架构·dubbo
砚边数影10 小时前
运营商网管系统重构:如何解决海量投诉数据下的“查询延迟”与“写入瓶颈”?
网络·数据库·时序数据库·kingbase·kingbasees·数据库平替用金仓·金仓数据库
shsh20010 小时前
mybatis plus打印sql日志
数据库·sql·mybatis
山峰哥10 小时前
数据库调优实战:索引策略与查询优化案例解析
服务器·数据库·sql·性能优化·编辑器
c***032311 小时前
MySQL 启动失败 (code=exited, status=1FAILURE) 异常解决方案
数据库·mysql
ritxgt00611 小时前
MySQL 数据增删改查
android·数据库·mysql
TimberWill11 小时前
SpringBoot整合Srping Security实现权限控制
java·spring boot·后端
t***442312 小时前
mysql之数字函数
数据库·mysql