说说在 MySQL 中一条查询 SQL 是如何执行的?
MySQL 执行一条查询 SQL 的流程分为 “客户端与服务器交互、服务器层处理、存储引擎层处理” 三个阶段,核心涉及连接器、查询缓存、分析器、优化器、执行器、存储引擎等组件,具体流程如下:
# 1. 阶段 1:客户端与服务器建立连接(连接器)
- 客户端通过 TCP/IP 协议与 MySQL 服务器建立连接,连接器验证用户名、密码(如
root用户的密码),并分配权限(如该用户是否有查询某表的权限); - 连接建立后,若客户端长时间无操作,连接器会自动断开连接(默认超时时间由
wait_timeout参数控制,默认 8 小时); - 核心作用:身份验证、权限分配、维持连接。
# 2. 阶段 2:查询缓存(MySQL 8.0 已移除)
- 若 MySQL 开启查询缓存(
query_cache_type=ON),服务器会先检查查询 SQL 是否在缓存中(缓存以 “SQL 语句” 为 key,查询结果为 value); - 若缓存命中(SQL 完全一致,区分大小写和空格),直接返回缓存结果,跳过后续分析、优化步骤;
- 若缓存未命中,继续执行后续流程;
- 核心问题:查询缓存失效频繁(如表数据更新时,该表的所有缓存都会失效),MySQL 8.0 已移除该功能,推荐用 Redis 实现应用层缓存。
# 3. 阶段 3:SQL 解析(分析器)
- 词法分析:将 SQL 语句拆分为 “Token”(如关键字
SELECT、表名user、字段名name、条件age>20); - 语法分析:根据 MySQL 语法规则,检查 SQL 语句的合法性(如
SELECT是否拼写错误、WHERE子句是否缺少条件),生成 “抽象语法树(AST)”; - 核心作用:验证 SQL 语法正确性,将 SQL 转换为机器可识别的语法结构。
# 4. 阶段 4:SQL 优化(优化器)
- 优化器的核心作用:在多个执行方案中选择 “成本最低” 的方案(成本包括 CPU 消耗、IO 消耗等);
- 主要优化操作:
- 选择索引:根据表统计信息(如索引 cardinality、数据分布),选择最优索引(如选择
idx_age而非全表扫描); - 调整关联顺序:多表关联时,选择小表作为驱动表(如
user表和order表关联,选择行数少的表作为驱动表); - 简化表达式:如
1+2=3优化为3,WHERE id=1 AND id=2优化为WHERE 1=2(恒假条件); - 改写 SQL:如
IN (1,2,3)改写为OR条件,LEFT JOIN优化为INNER JOIN(若条件允许);
- 选择索引:根据表统计信息(如索引 cardinality、数据分布),选择最优索引(如选择
- 输出结果:生成 “执行计划”(可通过
EXPLAIN命令查看,包含索引选择、关联顺序、扫描行数等信息)。
# 5. 阶段 5:SQL 执行(执行器)
- 执行器根据执行计划,调用存储引擎(如 InnoDB)的 API 执行查询:
- 权限校验:再次校验用户是否有查询表字段的权限(避免优化器阶段权限变更);
- 数据读取:根据执行计划,通过存储引擎读取数据(如通过索引
idx_age定位age>20的行,逐行返回); - 结果处理:将读取的数据按 SQL 要求过滤、排序(
ORDER BY)、分页(LIMIT),最终生成结果集;
- 核心作用:协调存储引擎执行查询,处理结果集。
# 6. 阶段 6:存储引擎层处理(如 InnoDB)
- 存储引擎负责数据的物理存储和读取,接收执行器的指令(如 “读取
user表中age>20的行”); - 若使用索引查询,InnoDB 通过聚簇索引或非聚簇索引定位数据(非聚簇索引需回表查询完整行数据);
- 若未使用索引,InnoDB 执行全表扫描(逐行读取数据,判断是否满足条件);
- 核心作用:提供数据的物理存储、索引访问、事务支持等底层能力。
# 总结流程
客户端连接 → (查询缓存,已移除) → 解析 SQL(分析器) → 优化 SQL(优化器) → 执行 SQL(执行器) → 存储引擎读取数据 → 返回结果集。
上次更新: 12/30/2025