内嵌视图必须显式命名别名,否则报错;它是在FROM中直接使用的子查询,属一次性临时表结构,非持久对象;标量子查询不可直接用于FROM,须返回带列名的表结构;深层嵌套阻碍条件下推,降低性能,MySQL 5.6及以下不支持。

内嵌视图必须显式命名别名,否则直接报错
所有主流数据库(PostgreSQL、SQL Server、MySQL 5.7+)都强制要求:子查询出现在 FROM 子句中时,必须用 AS alias 显式指定别名。不加会立刻失败,比如 MySQL 报 ERROR 1248 (42000): Every derived table must have its own alias。
别名要紧贴子查询右括号后写,不能拖到 WHERE 或其他位置;哪怕只查一列,(SELECT 1) t 合法,(SELECT 1) 就非法;别名若和外层字段名重复,可能引发列解析歧义,比如外层有 id 字段,内嵌视图别名也叫 id,就容易出问题。
普通视图是持久对象,内嵌视图是临时结构
普通视图通过 CREATE VIEW 创建,存于数据字典,可被反复引用、授权、依赖检查;内嵌视图只是 FROM 里的一个子查询,不入库、无元数据、生命周期仅限当前语句执行。
但执行时,普通视图会被数据库“展开”成等价的内嵌视图。例如 SELECT * FROM empvu30 实际等价于 SELECT * FROM (SELECT employee_id, last_name, salary FROM employees WHERE department_id = 30) empvu30 —— 所以优化器看到的,本质上都是内嵌视图。
这意味着:普通视图的嵌套层数越多,执行计划越难下推条件;而内嵌视图从一开始就没有“对象身份”,优化器更倾向于按字面结构处理,风险更直观。
标量子查询不能直接当表用,必须返回表结构
FROM 需要的是能参与连接、投影、过滤的“表结构”,至少有一行一列,且列要有明确名称。像 (SELECT COUNT(*) FROM users) 这种标量子查询,只返回单个值,没有列名定义,在 FROM 中会因语法或语义错误失败。
正确写法必须显式定义列:(SELECT COUNT(*) AS cnt FROM users) t;或者补全结构:(SELECT 1 AS id, COUNT(*) AS cnt FROM users) t。
反过来,在 WHERE 或 SELECT 列表里用标量子查询完全没问题,比如 WHERE id = (SELECT MAX(id) FROM logs) 是标准用法。
三层以上嵌套显著影响条件下推和索引使用
写成 SELECT * FROM (SELECT * FROM (SELECT * FROM orders WHERE status = 'shipped') t1) t2 WHERE user_id = 123 看似逻辑清晰,但多数优化器无法把 user_id = 123 下推到最内层 orders 表,导致先全量扫描所有 shipped 订单,再逐层过滤。
用 EXPLAIN 查执行计划时,重点看 rows 值是否远大于预期;如果内层已有 user_id 条件,应优先提到外层 WHERE,或改用 JOIN 拆解;MySQL 5.6 及更早版本甚至不支持这种写法,直接报 ERROR 1349 (HY000): View's SELECT contains a subquery in the FROM clause。
每多一层括号,优化器放弃下推的风险就高一分——这不是语法限制,而是现实引擎的妥协点。

















