mysql 8.0升级后视图查询变慢主因是优化器默认启用derived_merge=on和hash_join=off,导致条件无法下推、join退化为全表扫描或临时表物化;须手动展开视图用explain分析type/rows/extra,并调整optimizer_switch开关验证。

MySQL升级后视图查询变慢,大概率不是SQL写得差,而是优化器在8.0里默认启用了更激进的派生表合并策略,把原本能走索引的路径硬生生“优化”成了全表扫描或临时表物化。
为什么EXPLAIN看视图只显示derived却看不出问题
对视图直接跑EXPLAIN SELECT * FROM my_view,MySQL 8.0只会返回type=derived、key=NULL这种笼统提示。这是因为视图定义在执行阶段才展开,EXPLAIN无法穿透进去看真实JOIN路径。
- 必须手动展开:用
SHOW CREATE VIEW my_view拿到原始SELECT语句,把整个子查询贴出来再跑EXPLAIN - 重点盯
type字段:如果从ref变成ALL,说明索引失效;rows值暴涨10倍以上就是典型信号 -
Extra里出现Using temporary或Using filesort,尤其在performance_schema表上,基本等于性能已崩
关键optimizer_switch开关怎么调
MySQL 8.0默认启用derived_merge=ON和关闭hash_join=off,这两个开关最常让视图JOIN退化:
-
derived_merge=ON:强制把子查询“合并”进外层JOIN,导致本可下推的WHERE条件失效,先全量物化再过滤 -
hash_join=off:8.0引入哈希连接本是利好,但默认关闭;老SQL若靠嵌套循环硬扛,新版没开哈希连接,JOIN性能反而倒退 - 验证方式:
SET SESSION optimizer_switch='derived_merge=off,hash_join=on';后再EXPLAIN,观察type和rows是否回归正常
performance_schema视图卡死怎么绕过
像sys.innodb_lock_waits这类监控视图,在8.0中底层从information_schema.innodb_lock_waits切到了performance_schema.data_lock_waits,但后者记录的是“所有事务持有的锁”,数据量可能差几个数量级。
- 一个大事务锁住300万行,
data_lock_waits就生成300万条记录 - 每次查询该视图都要全表扫描+持有
trx_sys->mutex,阻塞所有新事务启动 - 解决方案不是调优,而是绕过:直接查基表
information_schema.INNODB_TRX+INNODB_LOCKS(5.7兼容路径),或改用sys.schema_table_statistics等轻量视图
视图里有UNION或嵌套子查询时怎么防物化膨胀
MySQL对含UNION或嵌套子查询的视图,默认倾向物化中间结果,一旦数据量上去,rows会指数级增长。
- 优先把聚合/过滤逻辑提到子查询里做,让外层只做简单关联,例如把
CASE WHEN状态计算封装进子查询,主表只LEFT JOIN结果集 - 避免
SELECT *:列序一变,下游按索引取值(如rs.getString(2))直接错位 - 禁用
DISTINCT和GROUP BY:除非绝对必要,它们会触发临时表和排序,放大物化开销
真正麻烦的不是参数开关本身,而是这些开关在不同视图结构下的组合效应——比如derived_merge=off能救JOIN,但可能让UNION子查询反复执行;hash_join=on加速大表关联,却对小表JOIN增加初始化成本。得结合EXPLAIN FORMAT=TREE逐层看执行树,而不是凭经验一刀切。











