MySQL 查询与更新语句执行过程深度解析:从原理到实践​ - 指南

news/2025/10/28 19:44:55/文章来源:https://www.cnblogs.com/yangykaifa/p/19172588

在日常研发中,我们每天都在与 MySQL 的SELECT查询和UPDATE更新语句打交道,但你是否真正了解这些语句在数据库内部是如何 “运转” 的?理解 MySQL 的执行流程,不仅能帮助我们写出更高效的 SQL 语句,还能在遇到性能问题时快速定位根源。本文将从 MySQL 的架构设计出发,详细拆解查询语句和更新语句的完整执行过程,带大家看透 SQL 背后的 “黑盒子”

一、MySQL 架构:语句执行的 “底层框架”​

要理解语句执行过程,首先需明确 MySQL 的三层逻辑架构,各层级协同工作,构成 SQL 处理的完整链路。

架构层级核心组件功能详解
连接层

连接器

连接池

1. 连接器:与客户端建立 TCP 连接,验证用户名密码,分配线程;

2. 连接池:复用空闲连接,减少 TCP 建立 / 断开开销,默认 8 小时超时回收

服务层分析器、优化器、执行器、查询缓存(8.0 + 废弃)1. 分析器:将 SQL 转化为抽象语法树(AST),校验语法与语义;2. 优化器:基于统计信息选择最优执行计划,如索引选择、JOIN 顺序;3. 执行器:调用存储引擎接口执行计划,处理权限二次校验
存储引擎层InnoDB、MyISAM1. InnoDB:支撑事务、行锁、MVCC,通过 Buffer Pool、日志系统实现高效读写;2. MyISAM:不承受事务与行锁,适用于只读场景,已逐渐被 InnoDB 取代

二、查询语句(SELECT)执行流程:6 步实现高效数据读取​

以实际业务场景中的查询为例:SELECT id, username FROM users WHERE age > 25 AND status = 1 LIMIT 20;,其执行过程可拆解为以下 6 个关键步骤。

步骤 1:建立连接 —— 语句执行的 “入口”​

  • 客户端通过mysql -u root -p等命令发起连接,连接器接收请求后:​

  1. 验证用户名、密码及数据库权限(如是否允许访问users表);​

  2. 分配独立线程处理该连接,避免线程安全问题;​

  3. 若连接池中有空闲连接,直接复用,无需重新建立 TCP 连接。​

  • 常见问题:若出现 “Too many connections” 错误,需检查max_connections配置(默认 151),或优化连接复用策略(如使用连接池设备 Druid)。

步骤 2:查询缓存(8.0 + 废弃)—— 性能优化的 “过去式”​

  • 在 MySQL 5.7 及之前版本,查询缓存会存储 SQL 语句与结果的键值对:​
  1. 若 SQL 完全匹配(字符、空格、大小写一致),直接返回缓存结果;​
  2. 但只要表数据发生修改(如 INSERT、UPDATE),关联缓存会全部清空,命中率极低。​
  • 为什么 8.0 + 会废弃?对于频繁更新的业务,缓存清空开销远大于查询加速收益,反而增加 CPU 负担。​

步骤 3:SQL 解析 —— 将 “自然语言” 转化为 “机器语言”

  • 分析器分两步处理 SQL:​
  1. 否匹配,若错误返回 “SQL syntax error”;​就是语法分析:校验 SQL 语法正确性,如SELECT是否拼写错误、括号
  2. 语义分析:验证表 / 字段存在性(如users表是否存在,age、status字段是否在表中),以及用户是否有查询权限。​
  • 最终输出:抽象语法树(AST),例如将WHERE age > 25 AND status = 1转化为树形结构,便于后续优化器处理。

步骤 4:执行计划优化 —— 选择 “最优路线”​

  • 优化器是查询性能的 “核心大脑”,基于表统计信息(如行数、索引区分度)选择执行计划:

  1. 否使用age或status字段的索引,若存在联合索引idx_age_status,则优先选择;​就是​索引选择:判断

  2. 过滤顺序:先过滤status = 1(基数低,过滤后数据量少),再过滤age > 25,减少后续计算量;​

  3. LIMIT 优化:提前终止扫描,避免全表遍历后再截取前 20 条信息。​

  • 如何查看执行计划?使用EXPLAIN命令,例如EXPLAIN SELECT ...,通过type字段(如range、ref)判断索引使用情况,rows字段评估扫描行数

步骤 5:执行 SQL—— 调用存储引擎实现素材读取​

  • 执行器根据优化器生成的计划,调用 InnoDB 接口获取数据:​
  1. 权限校验:再次确认用户有users表的SELECT权限(防止解析后权限变更);​

  2. 数据读取:​若使用索引:通过索引找到符合条件的主键 ID,再通过主键回表查询id、username字段(即 “书签查找”);​若全表扫描:从表的第一个数据页开始,逐行判断age > 25 AND status = 1,筛选符合条件的数据;​

  • 结果收集

步骤 6:返回结果 —— 分批次传输避免内存溢出​

  • 执行器将整理后的结果集,通过连接层的 TCP 连接返回给客户端:​

  1. 若结果集较大(如无 LIMIT 的大表查询),MySQL 会分批次返回,每次传输 16KB 材料;​

  2. 客户端接收数据后,按格式展示(如命令行以表格形式,Navicat 以列表形式)。

三、更新语句(UPDATE)执行流程:7 步保障事务一致性​

相比查询语句,更新语句(如UPDATE users SET username = 'new_name' WHERE id = 100;)需保证事务 ACID 特性,执行流程更复杂,涉及日志、锁机制。​

步骤 1:前期准备 —— 与查询语句共享基础流程​

与查询语句类似,更新语句先经过 “建立连接→SQL 解析→执行计划优化” 三步:​

  1. 解析器验证UPDATE语法正确性,确认users表及username、id字段存在;​

  2. 优化器选择最优索引(如id主键索引),生成 “通过主键定位行→修改字段” 的执行计划。​

步骤 2:加行锁 —— 防止并发修改冲突​

执行器定位到待更新行(id = 100)后,为该行加行级排他锁(X 锁):​

  1. 锁粒度:仅锁定当前行,其他行可正常修改,支持高并发;​

  2. 锁升级风险:若更新语句未使用索引(如WHERE age = 25且age无索引),InnoDB 会扫描全表,将所有行加行锁,最终升级为表锁,导致并发阻塞;​

  3. 锁释放时机:事务提交或回滚后释放,避免长期占用锁资源。​

步骤 3:生成 Undo Log—— 实现事务回滚​

在修改数据前,InnoDB 将 “修改前的旧数据” 写入 Undo Log(回滚日志):​

  1. 日志内容:users表id=100行,username旧值为'old_name';​

  2. 核心作用:​回滚:若事务执行ROLLBACK,通过 Undo Log 恢复数据到修改前状态;​MVCC:为读执行提供快照数据,实现 “读不加锁,写不阻塞读”。​

步骤 4:修改内存素材 —— 基于 Buffer Pool 提升性能​

InnoDB 不直接修改磁盘数据,而是先执行内存中的 Buffer Pool:​

  1. Buffer Pool 是内存缓存池,存储热点资料页的副本,访问速度比磁盘快 10 万倍;​

  2. 执行器调用 InnoDB 接口,将 Buffer Pool 中id=100行的username改为'new_name';​

  3. 标记脏页:修改后的内存数据页与磁盘素材不一致,被标记为 “脏页”,等待后续刷盘。​

步骤 5:生成 Redo Log—— 保障信息不丢失​

修改内存数据后,InnoDB 将 “修改操作” 写入 Redo Log(重做日志):​

  1. 日志类型:物理日志,记录 “数据页的修改位置与内容”,如 “修改 users 表资料页 1024 中 id=100 行的 username 字段”;​

  2. 写入机制:先写入 Redo Log Buffer(内存缓冲区),再通过fsync刷到磁盘文件,默认innodb_flush_log_at_trx_commit=1(事务提交时强制刷盘);​

  3. 循环写入:Redo Log 文件大小固定(如 2 个 4GB 文件),写满后覆盖旧日志,通过 LSN(日志序列号)管理写入位置。​

步骤 6:事务提交 —— 搞定数据持久化​

执行COMMIT命令后,MySQL 达成两项关键操作:​

  1. 刷写 Redo Log:将 Redo Log Buffer 中的日志强制刷到磁盘,确保即使宕机,日志也不会丢失;​

  2. 释放行锁:释放id=100行的 X 锁,允许其他事务修改该行数据;​

  3. 事务状态变更:将事务标记为 “已提交”,通知客户端更新成功。​

步骤 7:异步刷脏页 —— 平衡性能与一致性​

  • 事务提交后,脏页(内存中修改后的数据页)不会立即刷盘,而是由 InnoDB 后台线程(如 Page Cleaner 线程)异步处理:​

  1. 触发时机:​

  • Buffer Pool 空闲空间不足(如空闲率低于innodb_free_buffer_pool_pct阈值);​

  • Redo Log 即将写满(如使用率达到 75%);​

  • MySQL 空闲时(如夜间低峰期);​

2. 刷盘策略:采用 “批量刷盘”,每次刷写多个脏页,减少磁盘 IO 次数,提升性能。

四、查询与更新语句的核心差异对比​

凭借以上分析,可总结两种语句的关键区别,为性能优化给予方向:​

对比维度查询语句(SELECT)更新语句(UPDATE)
事务支持无需事务(除非显式开启)必须支持事务,依赖 Undo/Redo Log
锁操作无锁(或共享锁 S 锁,如SELECT ... FOR SHARE)加排他锁 X 锁,防止并发修改
日志写入不写入日志写入 Undo Log(回滚)、Redo Log(恢复)
数据修改仅读取数据,不修改磁盘 / 内存修改 Buffer Pool 数据,标记脏页,异步刷盘
性能瓶颈主要在索引优化(减少扫描行数)锁竞争、日志刷盘、脏页刷盘

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/949090.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ZKY精选冲刺省选国赛技巧训练题

Discrete Centrifugal Jumps CodeForces - 1407D 解题思路 代码实现点击查看代码序列妙妙值 UniversalOJ - 549 解题思路 代码实现点击查看代码Constrained Sums AtCoder - abc277_h 解题思路 代码实现点击查看代码ag…

逆向基础--编码(001)

逆向基础--编码(001)一.位与字节比特(Bit):1比特就是1位,每个0或1就是一个位,位是数据存储的最小单位。位是二进制表示,8位二进制是一个字节。 8位二进制(就是8个比特)最大:11111111字节(Byte):字节是通过网…

20251027 - 倍增 ST表

前言: 怎么标题改来改去的? 概念 因为每一个整数都可以转换成对应的二进制,所以可以表示成 \(a_0 \times 2^0 + a_1 \times 2 ^ 1 + a_2 \times 2 ^ 2 + a_{len} \times 2 ^ {len}\)。 因此,对于求跳 \(x\) 步后的…

周康阳精选冲刺省选国赛思维训练题

agc052_a Long Common Subsequence 解题思路 代码实现点击查看代码agc052_a Long Common Subsequence 解题思路 代码实现点击查看代码agc052_a Long Common Subsequence 解题思路 代码实现点击查看代码agc052_a Long C…

Luogu P7913 [CSP-S 2021] 廊桥分配 题解 [ 绿 ] [ 贪心 ] [ 前缀和 ] [ STL ]

廊桥分配 笑点解析:VP 的时候想这题想了 20min,比想 T3 的时间长。 关键结论:在不考虑廊桥限制的情况下,给每个飞机分配一个最小的廊桥编号。当最终廊桥数目大于等于其对应编号时,飞机才能被分配到廊桥。 理解起来…

10-27 CSP 赛前比赛记录

DNA 序列(DNA)哈希题啊,但是忘了怎么写哈希了 qwq,所以…… 思路大概就是维护一个长度为 \(k\) 的四进制数,类似于一个滑动窗口,就是除以 \(4\) 后加上右边新加的数乘上 \(4^k\),就可以得到其对应的哈希值,取模…

P3939 数颜色

这道题是暑假写的。但是当时数据结构学傻了,写了个莫队。 然后刚刚发现没过,连忙重新看题。 想了想发现跟可以跟Ynoi有一道区间众数题一个思路处理一下,直接二分就完了。 就记录一下每个数的出现次数。这里还有个小…

完整教程:Docker 搭建 Nginx 并启用 HTTPS 具体部署流程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

AI开发微信小程序-有感

我先有一版html代码(有一个个人网站,里面都是一些在线使用的工具) 抽取出了其中一个小功能,让AI根据现有html代码直接转成小程序 直接拿过来在微信小程序开发IDE上,进行测试 稍微调整一下,就OK了。 AI真的是太有…

价值流智能时代:DevOps平台如何成为企业高效交付的核心引擎? - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2025年压力容器品牌综合实力排行榜

文章摘要 随着化工、石油、能源等行业的快速发展,压力容器作为核心设备在工业生产中扮演着越来越重要的角色。2025年压力容器行业将更加注重技术创新、安全性能与环保标准,头部企业通过智能化制造与定制化服务持续提…

2025年压力容器厂家综合评测与选择指南

摘要 随着化工、石油、能源等行业的快速发展,压力容器作为核心设备在工业生产中扮演着越来越重要的角色。2025年压力容器行业将更加注重技术创新、安全性能和服务质量,市场竞争也日趋激烈。本文基于行业数据和技术参…

2025年口碑好的压力容器工厂/厂家前十强

文章摘要 压力容器行业在化工、石油、动力及食品等领域持续增长,2025年预计全球市场规模将达千亿美元,驱动因素包括工业自动化升级和环保要求提升。本文基于行业数据、用户口碑和技术参数,综合评测前十品牌,并提供…

AI Agent 从零到百万价值迭代之路 - 智慧园区

这个时代Agent的本质:用精心设计的prompt作为"控制语句",用LLM作为"解释器",构建一个能处理模糊输入的动态系统-互联网创业老兵大模型时代为什么是革命 经过了近2年的Agent开发,在法律、工业、…

项目构建优化:CMake

CMake 介绍 在 Linux 工程管理中,make 是常用的工程管理器,但它依赖的 Makefile 语法晦涩、编写复杂,尤其在多文件、跨平台项目中维护成本极高。为解决这一问题,主流方案有两种:使用 automake 生成 configure 脚本…

项目构建优化:Make 与 Makefile

项目构建优化背景与 Make 工具基础 项目构建的核心痛点 在模块化开发中,会将可复用的函数接口、数据结构封装为源文件(.c) 和头文件(.h) 。当项目规模扩大(如大型 C/C++ 项目、Linux 内核),源文件与头文件数量…

科幻——面包

“卖面包咯,卖面包咯”一个面包小贩的声音从街边传来,但毕竟卖不出去啊,哪个现代人还买路边摊上的面包呢?饥寒交迫而又无奈,真有点“现代卖炭翁”的感觉了。 有什么办法呢?自从专业坍塌的那一瞬间,它便看清了它…

2025年中国钢结构码垛机制造商Top 5排名解析

摘要 钢结构码垛机行业随着工业自动化浪潮的推进,正迎来快速增长期,预计2025年全球市场规模将突破百亿元,中国作为制造大国,占据重要份额。行业发展聚焦于智能化、高效化和定制化,企业竞相提升技术实力和服务水平…

2025年钢结构码垛机品牌前十强权威盘点:江苏众利达引领智能制造新浪潮

文章摘要 随着工业4.0时代的深入发展,钢结构码垛机行业正迎来智能化升级的关键时期。2025年全球智能码垛设备市场规模预计突破百亿美元,中国作为制造业大国占据近40%市场份额。本文基于技术参数、市场口碑、服务能力…

处理django.db.utils.OperationalError: attempt to write a readonly database错误

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …