MySQL 执行一条 select 语句,期间发生了什么? 一问一答MySQL 执行一条 select 语句期间发生了什么问MySQL 执行一条 select 语句期间到底发生了什么答想要搞懂这个问题首先要先明白 MySQL 的整体架构它整体分为Server 层和存储引擎层两大块。一条 select 语句的完整执行流程就是依次走完 Server 层的连接器、查询缓存、解析器、预处理器、优化器、执行器最后由执行器调用存储引擎的接口获取数据我一步步给你拆解清楚每个环节都做了什么。第一步连接器 —— 建立连接、校验身份、管理权限客户端要执行 SQL第一步肯定是和 MySQL 服务建立连接这个工作就是连接器来做的。首先会通过 TCP 三次握手和 MySQL 服务建立连接毕竟 MySQL 是基于 TCP 协议传输的然后校验你输入的用户名和密码不对就直接返回Access denied报错终止执行账号密码校验通过后连接器会读取你这个账号的权限后续这个连接里的所有操作都会基于此时读取到的权限来做校验 —— 哪怕中途管理员改了你的权限也不会影响已经建立好的连接只有新建连接才会用新权限。这里还有几个面试常问的加分细节怎么看当前有多少客户端连接执行show processlist就能看到所有连接包括空闲连接、正在执行的查询空闲连接不会一直占着资源MySQL 默认 8 小时会自动断开空闲连接由wait_timeout参数控制也能手动用kill connection 连接id断开MySQL 的连接数是有限制的默认最大 151 个超过就会报Too many connections拒绝连接推荐用长连接而不是短连接长连接能减少频繁建连、断连的 TCP 握手挥手开销不过长连接多了会占用更多内存我们线上会定期重置连接或者用 MySQL 5.7 的mysql_reset_connection接口释放内存。第二步查询缓存 —— 命中直接返回8.0 版本已彻底移除连接建立完成后客户端发送 select 语句MySQL 会先去查查询缓存。它是以 key-value 形式存在内存里的key 就是完整的 SQL 语句value 就是查询的结果。如果这条 SQL 之前执行过缓存里有就直接把结果返回给客户端不用往下走了如果没命中缓存就会继续往下执行等查询执行完还会把结果存入查询缓存。但这里要重点说MySQL 8.0 版本直接把查询缓存整个删掉了因为它非常鸡肋坑特别多只要表有任何更新操作这个表对应的所有查询缓存都会被清空。对于频繁更新的业务表缓存命中率极低经常是刚缓存上还没来得及用就被清空了完全是负优化。如果是 8.0 之前的版本我们也会把query_cache_type设为 DEMAND默认关闭查询缓存。第三步解析器 —— 词法分析 语法分析拆解 SQL如果缓存没命中就会进入解析器环节它的核心工作就是 “看懂” 你写的 SQL。词法分析把你写的 SQL 字符串拆成一个个 Token识别出关键字和非关键字。比如select * from product where id 1会识别出select、from、where这些关键字还有product表名、id字段名这些非关键字语法分析根据 MySQL 的语法规则判断你写的 SQL 有没有语法错误没问题的话就构建出一棵语法树方便后面的模块获取 SQL 类型、表名、字段名、where 条件这些信息。如果 SQL 语法写错了比如把from写成form就会在这个阶段报语法错误。这里有个细节要注意解析器只校验语法不会检查表、字段是否存在这个工作是后面的预处理器做的。第四步预处理器 —— 校验表和字段补全 SQL 信息解析器生成语法树后就会进入预处理器做合法性校验和 SQL 补全检查 SQL 里的表、字段是否真的存在不存在就会报Table doesnt exist或者未知字段的错误把select *里的*自动扩展成表上的所有列校验权限看你这个账号有没有查询这个表的权限没权限直接报错。第五步优化器 —— 生成最优的执行计划预处理完成后SQL 的合法性已经确认了接下来优化器就要决定 “这条 SQL 该怎么执行最快”。优化器的核心工作就是基于查询成本给 SQL 选一个最优的执行方案比如表里有多个索引的时候优化器会判断用哪个索引查询成本最低甚至有时候会判断全表扫描比走索引还快就会放弃索引走全表扫描像我们这条select * from product where id 1id 是主键优化器就会直接选择走主键索引。面试里常问的explain关键字就是用来查看优化器生成的执行计划看 SQL 到底走没走索引、走了哪个索引。第六步执行器 —— 调用存储引擎执行计划返回结果优化器确定了执行计划后就会把执行计划交给执行器由执行器真正去执行 SQL。执行器的工作流程很清晰先判断你有没有查询这个表的权限没权限直接报错有权限的话就根据执行计划调用存储引擎提供的 API 接口去读取对应的数据把存储引擎返回的结果组装成结果集返回给客户端整条 select 语句就执行完成了。比如我们这条 SQL执行器会调用 InnoDB 存储引擎的接口去主键索引里查 id1 的记录把结果返回给客户端。如果是没有索引的查询执行器就会调用存储引擎的接口一行行扫描全表把符合条件的行收集起来返回。最后总结一条 select 语句的完整执行链路就是客户端 TCP 建连 → 连接器校验身份权限 → 查询缓存8.0 无 → 解析器做词法 / 语法分析 → 预处理器校验表字段合法性 → 优化器生成最优执行计划 → 执行器调用存储引擎接口取数据 → 返回结果给客户端。专家图像生成PPT 生成