SQL 语句在 MySQL 执行过程

SQL SELECT 语句执行过程

SQL Select 语句整个查询执行过程,总的来说分为 6 个步骤 :

  1. 连接:客户端向 MySQL 发送一条查询请求
    • 客户端与服务器建立连接:通过TCP/IP、Unix套接字或命名管道等方式
    • 身份验证:验证用户名、密码和主机权限
    • 连接管理:服务器为每个连接分配线程,通过SHOW PROCESSLIST可查看
    • 会话变量设置:根据配置文件或用户请求初始化会话环境
  • 与 MySQL 建立的连接,是由连接器 Connectors 来完成的

  • 客户端如果长时间没有和 MySQL 产生交互,连接器就会自动将此次连接断开;这个时间是由参数 wait_timeout 控制的,默认值是8小时。如果连接被断开之后,客户端若再次发送请求会收到一个错误 的提醒:Lost connection to MySQL server during query

  • 客户端与 MySQL 建立连接的过程是比较复杂繁琐的,建议在使用中要尽量减少建立连接的动作,尽量 使用长连接。但是若全部使用长连接,有时候会导致 MySQL 的占用内存飞速飙升,这是因为 MySQL 在 执行过程中临时使用的内存是管理在连接对象里面的。这些资源只有在连接断开的时候才释放。所以如果 长连接累积下来,可能导致内存占用太大,被系统强行杀掉(OOM),从现象看就是 MySQL 异常重启了

长连接和短链接:

  • 长连接是指连接成功后,如果客户端持续有请求,则一直使用同一个连接
  • 短连接是指每次执行完很少的几次查询就断开连接,下次查询再重新建立一个
  1. 缓存:服务器会先检查查询缓存,如果命中缓存,则直接返回缓存结果,否则进入下一阶段
    • 缓存查找:MySQL 将 SELECT 语句作为 key 在查询缓存中查找
    • 缓存条件:要求 SQL 语句完全一致(包括空格、大小写)
    • 缓存失效:表数据修改会导致相关缓存全部失效
    • 缓存配置:通过query_cache_typequery_cache_size参数控制
    • 注意:MySQL 8.0已移除查询缓存功能,因维护缓存开销常大于收益
  2. 解析:服务器进行 SQL 解析(词法语法)、预处理
    • 词法分析:将 SQL 语句分解为令牌(tokens),识别关键字、表名、列名等
    • 语法分析:检查 SQL 语法是否正确,构建解析树
    • 语义检查:验证表、列是否存在,用户是否有权限
    • 视图展开:如果查询涉及视图,将视图替换为定义
    • 预处理:处理表达式,进行常量折叠等优化
  3. 优化:再由优化器生成对应的执行计划
    • 查询重写:优化器可能重写查询以提高效率
    • 执行计划生成:
      • 选择使用哪些索引
      • 决定表的连接顺序(对于多表查询)
      • 评估全表扫描与索引扫描的成本
      • 考虑使用临时表或文件排序
    • 统计信息使用:基于表的统计信息(行数、索引基数等)做出决策
    • 优化器提示:用户可通过FORCE INDEX等提示影响优化器决策
  4. 执行:MySQL 根据执行计划,调用存储引擎的 API 来执行查询
    • 执行引擎:调用存储引擎 API 获取数据
    • 索引使用:根据执行计划使用相应的索引
    • 表扫描:如果需要,执行全表扫描
    • 连接操作:执行嵌套循环连接、哈希连接或排序合并连接
    • 排序分组:执行 ORDER BY、GROUP BY 等操作
    • 临时表:必要时创建临时表处理中间结果
  5. 结果:将结果返回给客户端,同时缓存查询结果
    • 结果集生成:将数据组装成客户端需要的格式
    • 网络传输:通过连接将结果发送给客户端
    • 增量返回:对于大结果集,可能分批返回
    • 缓存写入:如果查询缓存开启且查询可缓存,将结果存入缓存
    • 资源清理:释放执行过程中使用的临时资源

SQL Update 语句执行过程

更新语句在执行时也会先走一遍同样的查询语句的流程

MySQL 整个更新的执行过程,总的来说分为 5 个步骤 :

执行的更新 SQL:update t_student set age=age+1 where id=2

  1. 客户端向 MySQL 服务器发送一条更新请求
    • 客户端与MySQL服务器建立连接后发送 UPDATE 语句
    • 服务器接收 SQL 文本并进行初步校验(如连接权限检查)
    • 如果是事务中操作,会检查当前事务状态(活跃/已提交/已回滚)
  2. 清除表查询缓存 ,跟这个有关的查询缓存会失效。这就是一般不建议使用查询缓存的原因
    • 立即失效化:标记与该表相关的所有查询缓存条目为无效
    • 缓存维护开销:这是查询缓存的主要缺点之一,任何修改操作都会导致相关缓存失效
    • 性能影响:对于写频繁的应用,维护缓存的开销可能超过收益
    • 注意:MySQL 8.0+已完全移除查询缓存功能
  3. 分析器进行 SQL 解析(词法和语法分析),分析这是一条更新语句
    • 词法分析:将UPDATE语句拆解为token(识别关键字、表名、列名等)
    • 语法分析:验证SQL语法结构是否正确(如SET子句格式、WHERE条件等)
    • 语义检查:
      • 验证目标表和列是否存在
      • 检查用户是否有UPDATE权限
      • 验证WHERE条件中引用的列是否存在
    • 预处理:展开视图、处理表达式等
  4. 优化器生成对应的执行计划,优化器决定使用 id 索引
    • 索引选择:基于WHERE条件选择最优索引(如例中的id索引)
    • 访问路径决策:决定使用索引扫描还是全表扫描
    • 成本评估:估算不同执行计划的I/O和CPU成本
    • 连接顺序:如果是多表UPDATE,确定表连接顺序
    • 生成计划:最终确定执行方案,包括使用的索引和访问方法
  5. 执行器负责更新,找到这一行,然后进行更新:
    • 行定位:通过选定索引定位到要修改的行(如果 id=2 这一行所在的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回【MySQL 8.0后已取消查询缓存】)
      • 如果使用索引:
        • 通过执行器会逐行扫描,检查是否符合 WHERE 条件,效率较低索引快速定位到目标行(减少 I/O 开销)
        • 如果索引是二级索引(非主键),还需要回表查询聚簇索引(主键索引)获取完整数据
      • 如果没有索引(全表扫描):
        • 执行器会逐行扫描,检查是否符合 WHERE 条件,效率较低
    • 获取行锁(并发控制):MySQL 采用锁机制和 MVCC 来保证事务的隔离性
      • InnoDB 行锁:
        • 对符合条件的行加 排他锁(X锁) ,防止其他事务同时修改
        • 如果 WHERE 条件无法走索引,可能会 锁表 (如 UPDATE table WHERE name LIKE '%abc%'
      • MVCC(读已提交/可重复读隔离级别):
        • 读取数据时,基于 ReadView 判断可见性(避免脏读、不可重复读)。
        • 更新时,会检查该行是否被其他事务修改(冲突检测)
    • 写入 undo log(回滚日志):在修改数据前,InnoDB 会先记录 undo log (撤销日志)
      • 用于事务回滚(ROLLBACK
      • 支持 MVCC,让其他事务能读取修改前的数据(一致性读)
    • 修改内存中的数据页:InnoDB 不会直接修改磁盘数据,而是先更新 Buffer Pool(缓冲池) 中的缓存页
      • 从磁盘加载数据页到 Buffer Pool(如果不在内存)
      • 在内存中修改数据(此时磁盘数据仍是旧的)
      • 标记该页为 脏页(Dirty Page) ,后续由后台线程刷盘
    • 写入 redo log:为了保证数据持久性(Durability),InnoDB 会记录 redo log
      • 用于崩溃恢复(即使 MySQL 宕机,也能恢复已提交的事务)
      • 采用 WAL(Write-Ahead Logging) 机制,先写日志再写数据
    • 提交事务:事务提交(显式或隐式),InnoDB 会进行以下操作
      • 写入 binlog(二进制日志):
        • 用于主从复制(Replication)和点时间恢复(PITR)
        • 采用 两阶段提交(2PC) 保证 redo log 和 binlog 的一致性
      • 释放锁:释放行锁,其他事务可以访问该行
      • 刷盘(可选):
        • 根据 sync_binloginnodb_flush_log_at_trx_commit 决定是否立即刷盘
相关推荐
likangbinlxa4 分钟前
【Oracle11g SQL详解】UPDATE 和 DELETE 操作的正确使用
数据库·sql
r i c k32 分钟前
数据库系统学习笔记
数据库·笔记·学习
野犬寒鸦1 小时前
从零起步学习JVM || 第一章:类加载器与双亲委派机制模型详解
java·jvm·数据库·后端·学习
IvorySQL2 小时前
PostgreSQL 分区表的 ALTER TABLE 语句执行机制解析
数据库·postgresql·开源
·云扬·2 小时前
MySQL 8.0 Redo Log 归档与禁用实战指南
android·数据库·mysql
IT邦德2 小时前
Oracle 26ai DataGuard 搭建(RAC到单机)
数据库·oracle
惊讶的猫2 小时前
redis分片集群
数据库·redis·缓存·分片集群·海量数据存储·高并发写
不爱缺氧i2 小时前
完全卸载MariaDB
数据库·mariadb
纤纡.2 小时前
Linux中SQL 从基础到进阶:五大分类详解与表结构操作(ALTER/DROP)全攻略
linux·数据库·sql
jiunian_cn3 小时前
【Redis】渐进式遍历
数据库·redis·缓存