mysql执行select语句经历连接→解析→优化→执行→返回结果五阶段;explain仅模拟优化器预判,受统计信息过期、绑定变量、缓存等影响;slow_log中rows_examined、tmp_tables等指标可定位各阶段瓶颈;optimizer_trace能深入分析优化器决策依据。

SQL 查询在 MySQL 中到底经历了哪些阶段
MySQL 执行一条 SELECT 语句,并不是直接去磁盘捞数据然后返回。它会经过多个明确的内部阶段,每个阶段都可能成为性能瓶颈或出错源头。
典型流程是:连接 → 解析 → 优化 → 执行 → 返回结果。其中「解析」和「优化」阶段用户不可见但影响极大;「执行」阶段的行为则直接受索引、表结构、隔离级别等约束。
为什么 EXPLAIN 看到的执行计划和实际执行不一致
EXPLAIN 只模拟优化器的预判路径,不真正执行 SQL,所以它不会反映运行时才暴露的问题:
本文介绍了Python操作MYSQL、执行SQL语句、获取结果集、遍历结果集、取得某个字段、获取表字段名、将图片插入数据库、执行事务等各种代码实例和详细介绍,代码居多,是一桌丰盛唯美的代码大餐。如果想查看在线版请访问:https://www.jb51.net/article/34102.htm
- 统计信息过期(
ANALYZE TABLE未触发,导致优化器误判行数) - 绑定变量值不同引发不同的执行计划(尤其在
PREPARE/EXECUTE场景下) - 查询缓存(MySQL 8.0 已移除)或 Query Cache 开关状态影响是否走缓存路径
- 临时表或文件排序实际发生时,
EXPLAIN不显示磁盘 I/O 开销
从 slow_log 能看出哪个阶段出了问题
慢查询日志里关键字段如 Rows_examined、Rows_sent、tmp_tables、sort_merge_passes 都指向具体阶段:
-
Rows_examined显著大于Rows_sent→ 扫描过多行,可能是缺少索引或索引未命中(解析/执行阶段低效) -
tmp_tables > 0且tmp_table_sizes较大 → 优化器选择了基于磁盘的临时表(优化阶段决策失败) -
sort_merge_passes > 0→ 文件排序次数多,说明sort_buffer_size不足或无法利用索引排序(执行阶段资源受限) -
Query_time高但Lock_time也高 → 锁等待发生在执行阶段前的加锁环节(InnoDB 行锁/间隙锁竞争)
optimizer_trace 能帮你定位优化器“想错了”的地方
开启 optimizer_trace 后,MySQL 会记录优化器每一步的代价估算和最终选择依据,对理解“为什么没走索引”特别有用:
- 需先执行
SET optimizer_trace="enabled=on",再运行目标 SQL - 结果存在
information_schema.OPTIMIZER_TRACE表中,查TRACE字段 JSON 内容 - 重点关注
rows_estimation中各访问路径的预估行数、considered_execution_plans中被放弃的理由(比如 "Range checked for each record (index map: 0x1)") - 注意该功能有性能开销,仅用于诊断,不要长期开启
真正卡住查询的,往往不是语法写错,而是优化器在毫秒级内做的一个“看起来合理”的错误选择——而这个选择背后,是统计信息、索引设计、参数配置共同作用的结果。盯着 EXPLAIN 和 optimizer_trace 对比看,比反复改 SQL 更有效。









