视图嵌套超3层时优化器主动跳过重写流程,而非重写失效;mysql 5.7前默认关闭视图合并,sql server与postgresql在≥4层时因代价估算失效而终止条件下推和等价变换。

视图嵌套超3层时优化器直接放弃重写
不是“重写没生效”,而是数据库内核主动跳过整个重写流程——MySQL 5.7 及以前默认关闭视图合并(merge),SQL Server 和 PostgreSQL 在嵌套 ≥4 层后,也会因代价估算失效而终止条件下推和等价变换。你写的 WHERE user_id = 123 看似加在外层,实际根本没传进最内层的 orders 扫描节点。
子查询被原样复制,不是复用中间结果
视图只是文本模板,不是缓存快照。当 v_active_orders 引用了含子查询的 v_user_summary,优化器不会执行一次 v_user_summary 再复用,而是把它的完整定义“粘贴”进每一处调用位置。典型表现:
-
EXPLAIN显示同一子查询逻辑重复出现多次 -
DEPENDENT SUBQUERY(MySQL)或Correlated Subplan(PostgreSQL)节点频出 - 外层过滤字段在执行计划里只出现在顶层 Filter,底层基表扫描仍是
type=ALL或Seq Scan
列名模糊和 NULL 传播让重写逻辑不可靠
一旦嵌套中出现同名列(如 SELECT a.id, b.id)、别名未显式声明、或子查询返回可能为 NULL 的字段,优化器就无法安全做谓词下推或连接消除。例如:
- 建视图时漏写
a.id AS a_id,导致视图定义报错ERROR 1059 (42000): Identifier name 'id' is too long - 子查询里用
NOT IN (SELECT status FROM logs),而logs.status允许NULL,则整个条件恒为UNKNOWN,优化器干脆放弃重写该分支 -
SELECT *出现在任意一层 CTE 或子查询中,会阻止列剪枝,使外层WHERE无法穿透到基表
真正卡点:你没法靠 EXPLAIN 看清哪一层断了
EXPLAIN ANALYZE 显示的是最终执行路径,不反映嵌套展开过程。你看到 Seq Scan on v_orders_summary,但不知道它背后是否已展开成 v_customers → v_regions → customers 三层;更难发现 WHERE country = 'CN' 实际只作用于视图输出,从未落到 regions 表上。验证必须人工拆解:单拎最内层子查询,手动加上相同 WHERE 条件跑一遍,对比行数和索引命中情况——这才是唯一可信的断点定位方式。










