视图查询变慢应先检查是否被自动合并:MySQL 5.7默认启用derived_merge优化,遇GROUP BY、DISTINCT等会失效,UPDATE/DELETE中直接报错;可用EXPLAIN查select_type为DERIVED确认物化生效,推荐建视图时显式指定ALGORITHM=TEMPTABLE并确保materialization=on。

视图查询变慢,先看是否被自动合并了
MySQL 5.7 默认启用 derived_merge 优化,会把简单视图“展开”成原始 SQL 再执行。这在多数场景下更快,但一旦视图里含 GROUP BY、DISTINCT、SUM() 或 LIMIT 等结构,合并就失效;更麻烦的是,如果这个视图又被用在 UPDATE 或 DELETE 的 FROM 子句中,直接报错 ER_UPDATE_TABLE_USED。
验证方式很简单:
SELECT @@optimizer_switch LIKE '%derived_merge=on%';
若返回 1,说明合并已开启。此时可临时禁用它来测试性能变化:
SET SESSION optimizer_switch='derived_merge=off';
- 禁用后视图强制物化,生成临时表,避免重复计算
- 但要注意:物化表无索引(除非优化器自动加哈希索引),大结果集可能落到磁盘,反而更慢
- 仅对当前 session 生效,不影响其他连接
ALGORITHM = TEMPTABLE 是最稳的物化控制方式
比起动态开关 optimizer_switch,在建视图时显式指定 ALGORITHM = TEMPTABLE 更可靠——它绕过所有合并逻辑,强制走物化路径,且不受 derived_merge 设置影响。
例如原视图:
CREATE VIEW v_user_stats AS SELECT user_id, COUNT(*) cnt FROM orders GROUP BY user_id;
改成:
CREATE ALGORITHM = TEMPTABLE VIEW v_user_stats AS SELECT user_id, COUNT(*) cnt FROM orders GROUP BY user_id;
- 后续任何
SELECT * FROM v_user_stats WHERE cnt > 100都只执行一次聚合,结果缓存在内存或临时表中 - 如果视图被多次引用(比如 JOIN 多次),物化优势更明显
- 注意:不能和
ALGORITHM = MERGE混用;若已有视图需修改,得DROP后重建
物化是否生效?查 EXPLAIN 中的 select_type
真正判断优化是否落地,不能只看执行时间,要盯 EXPLAIN 输出里的 select_type 字段:
- 看到
DERIVED:说明该子查询/视图已被物化,对应行是临时表来源 - 看到
PRIMARY或SIMPLE:大概率被合并了,SQL 被重写为单层查询 - 若出现
UNION RESULT或MATERIALIZED(MySQL 8.0+),5.7 不会出现后者,DERIVED就是物化的唯一信号
特别提醒:如果物化表数据量大(比如上百万行),DERIVED 行的 rows 值可能不准,实际扫描量得结合 Handler_read_* 状态变量观察。
materialization 开关必须打开,否则物化不触发
视图物化依赖底层子查询物化能力,而子查询物化由 optimizer_switch 的 materialization 标志控制。MySQL 5.7 默认开启,但某些定制镜像或运维脚本可能关掉它:
SELECT @@optimizer_switch LIKE '%materialization=on%';
若为 0,需显式开启:
SET GLOBAL optimizer_switch='materialization=on';
- 该设置影响所有新连接,旧连接需重连才生效
-
materialization主要作用于IN、ANY、ALL子查询,但视图内部的子查询也受其调控 - 与
derived_merge=off配合使用效果最稳:一个禁合并,一个保物化
复杂视图里嵌套子查询时,这两个开关缺一不可;漏掉 materialization,即使 ALGORITHM = TEMPTABLE,内部子查询仍可能被反复执行。


















