是,mysql 5.6 到 8.0 的 select 查询主干流程仍为连接→解析→优化→执行→返回结果,但优化器(如 hash_join 默认启用、semi-join 行为)、group by/order by 默认策略、执行细节(如 kill query 行为、performance_schema 默认开启)及统计信息采样等存在显著版本差异。

MySQL 查询执行流程的核心阶段是否随版本变化
不会发生根本性变化。从 MySQL 5.6 到 8.0,SELECT 查询的主干流程仍为:连接 → 解析 → 优化 → 执行 → 返回结果。但每个阶段内部的具体实现、默认行为、可选策略和触发条件存在显著差异,尤其在查询优化器和执行引擎层面。
MySQL 5.7 和 8.0 在优化器行为上的关键差异
MySQL 8.0 引入了重构的优化器框架(如 Hypergraph Optimizer 实验性支持)、更激进的子查询展开、默认启用 hash_join(5.7 仅支持 BNL 或 Block Nested-Loop),且 IN 子查询默认转为半连接(semi-join),而 5.7 需显式开启 optimizer_switch='semijoin=on'。
-
JOIN算法选择逻辑不同:8.0 中EXPLAIN显示Using join buffer (hash join)是常态;5.7 只会显示Using join buffer (Block Nested Loop) -
GROUP BY默认行为变更:8.0 默认按sql_mode启用ONLY_FULL_GROUP_BY,5.7 默认关闭,易导致隐式聚合结果不一致 -
ORDER BY优化退化风险:8.0 对含函数的ORDER BY(如ORDER BY UPPER(name))更倾向使用 filesort;5.7 在某些索引覆盖场景下可能避免
执行阶段中容易被忽略的版本相关陷阱
执行计划看似相同,但底层行为可能已变。例如 Handler_read_* 状态变量含义未变,但实际调用路径受存储引擎接口演进影响(如 InnoDB 8.0 的 row_search_mvcc 调用栈更复杂);又如 information_schema.PROCESSLIST 中 STATE 字段在 8.0 新增了 Executing hook on transaction begin 类状态,5.7 不会出现。
- 8.0 默认启用
performance_schema且采集粒度更细,开启events_statements_history_long可能明显拖慢高并发短查询场景,5.7 默认关闭该消费者 -
PREV_EXEC_TIME在 8.0 的sys.statement_analysis视图中才开始统计,5.7 无对应字段 - 8.0 中
KILL QUERY对正在执行UNION的语句可能中断不彻底(因多线程执行分支),5.7 多为单线程顺序执行,中断更确定
如何验证当前版本的实际执行路径
不能只看 EXPLAIN 输出,要结合运行时指标与源码级线索。重点检查三类输出:
SELECT @@version, @@optimizer_switch\G SHOW VARIABLES LIKE 'optimizer_switch'; EXPLAIN FORMAT=TREE SELECT ...; -- 仅 8.0+ 支持
对关键查询,务必开启 optimizer_trace 并检查 trace 字段中的 steps 数组,它会明确写出“尝试了 hash_join”或“跳过 semijoin conversion”等决策依据——这部分内容在 5.7 和 8.0 的 JSON 结构、字段名甚至嵌套深度上都有区别。
真正麻烦的不是流程变了,而是同样一条 SQL,在 5.7 走了索引合并,在 8.0 却因为统计信息采样方式更新(innodb_stats_persistent_sample_pages 默认值从 20 升到 100)而选了全表扫描,且你从 EXPLAIN 看不出采样差异来源。










