merge算法决定视图能否走索引、是否可更新及锁行为,explain中出现select_type=derived即表明merge失效而降级为temptable;含聚合、distinct、子查询、union、order by等结构会强制降级,且algorithm=undefined仅静态判断一次,不可控。

MERGE 算法不是“可选优化”,而是决定视图能否走索引、是否可更新、会不会锁全表的关键开关;写 ALGORITHM = MERGE 不等于它真在用 MERGE,MySQL 会在你没注意时静默降级为 TEMPTABLE。
为什么 EXPLAIN 显示 select_type = DERIVED 就说明 MERGE 失效了
MySQL 执行视图时,若实际走的是 TEMPTABLE,优化器会把视图当作一个派生表(DERIVED)处理:先执行视图定义、物化进临时表,再对外层查询做二次扫描。这会导致:
-
type列常为ALL或index,基表索引基本失效 -
Extra中出现Using temporary或Using filesort - WHERE 条件无法下推到基表,只能在临时表上过滤
- 大结果集时内存/磁盘临时表开销陡增,QPS 明显下跌
反过来说,只要 EXPLAIN SELECT * FROM my_view WHERE x = 1 的输出里没有 DERIVED,且 type 是 ref 或 range,就大概率是 MERGE 生效了。
哪些写法会让 ALGORITHM = MERGE 被忽略
哪怕你明明白白写了 ALGORITHM = MERGE,只要视图定义中含以下任一结构,MySQL 就会直接无视该声明,强制改用 TEMPTABLE:
-
COUNT()、SUM()、AVG()等聚合函数 -
DISTINCT或GROUP BY - 任何子查询——包括
SELECT (SELECT ...)、FROM (SELECT ...)、WHERE id IN (SELECT ...) -
UNION、LIMIT、ORDER BY(除非配合LIMIT且无歧义) - 列重命名使用表达式导致类型不一致,例如
id + 0 AS id
验证方式不是看 SHOW CREATE VIEW 里写了什么,而是执行 EXPLAIN —— 输出里的 Algorithm 字段(5.7+)或 select_type 才是真实依据。
为什么 MERGE 视图能 UPDATE 而 TEMPTABLE 一定只读
MERGE 的本质是文本合并:执行 UPDATE v SET name = 'a' WHERE id = 1 时,MySQL 把这条语句和视图定义拼成一条完整 SQL,直接下推到基表执行,保留主键、索引、行锁上下文。
TEMPTABLE 则必须先生成一张无元数据的临时表(无主键、无索引、无外键),再对这张表操作——它根本不知道哪一行对应基表哪一行,所以连 WHERE 都没法安全映射,更别说加锁更新了。
这意味着:
- 只有
ALGORITHM = MERGE的视图才可能支持INSERT/UPDATE/DELETE(还需满足单表、无计算列等条件) -
WITH CHECK OPTION只对MERGE视图生效;TEMPTABLE下该子句被完全忽略 - 如果业务依赖视图写入能力,却误用了
TEMPTABLE,错误通常表现为ERROR 1288 (HY000): The target table v of the UPDATE is not updatable
ALGORITHM = UNDEFINED 并不“智能”,它只是放弃控制权
UNDEFINED 不是运行时动态决策,而是在 CREATE VIEW 时做一次静态判断:满足 MERGE 条件就固化为 MERGE,否则直接设为 TEMPTABLE。问题在于:
- 它不会随基表结构变化重新评估——比如后续给基表加了生成列或触发器,原先能用 MERGE 的视图在
ALTER VIEW后可能突然退化 - 你无法从语句本身预判结果,得靠
EXPLAIN实测 - 团队协作时,别人改了视图定义但没跑
EXPLAIN验证,性能或更新能力就可能悄无声息地崩掉
真正可控的做法,是让视图定义足够“干净”:去掉所有触发降级的语法糖,哪怕牺牲一点抽象便利,也要换回执行路径的确定性——尤其是线上核心视图。











