视图查询比原表慢的根本原因是外层where条件未下推至基表扫描,导致先物化中间结果再过滤;典型执行计划特征为materialize/using temporary/table spool,诱因包括group by、distinct、union、窗口函数、嵌套过深及select*或字段表达式。

视图查询比原表慢,不是因为“视图本身有开销”,而是外部 WHERE 条件大概率没落到基表扫描上——优化器被迫先算完视图结果,再过滤,中间结果集越大,越卡。
执行计划里出现 Materialize / Using temporary 就是铁证
这是最直接的判断依据。不同数据库表现略有差异:
- PostgreSQL:执行计划中看到
Materialize节点,尤其在视图展开后出现在基表上方 - SQL Server:出现
Table Spool或Compute Scalar后紧跟大范围Filter - MySQL:
type = ALL且Extra含Using temporary,哪怕你加了WHERE user_id = 123
这些节点意味着:数据库把视图当成一个独立中间表物化出来了,而不是把它逻辑展开、把外层条件下推到基表扫描环节。
GROUP BY、DISTINCT、UNION、窗口函数会强制物化
只要视图定义里含以下任一结构,谓词下推基本失效:
-
GROUP BY(哪怕只分组一个字段) -
DISTINCT(去重必须等全部数据产出后才能判) -
UNION(合并前两路结果需各自完成) - 窗口函数如
ROW_NUMBER()、RANK() - 子查询(尤其是相关子查询或标量子查询)
MySQL 尤其敏感:ALGORITHM = TEMPTABLE(默认行为之一)会彻底绕过基表索引;哪怕你 SELECT * FROM v_user WHERE id = 123,它也先全量物化视图,再筛第 123 行。
嵌套三层以上,下推大概率断掉
视图 A → B → C 这种链式嵌套,优化器对中间结果集大小估算偏差极大。一旦某层用了 LIMIT、OFFSET 或聚合,就容易:
- 连接顺序错乱(本该用小结果集驱动大表,结果反了)
- 驱动表选反(比如用百万行表去 JOIN 十万行表)
- 直接放弃下推所有外层
WHERE条件
验证方法很简单:用 pg_get_viewdef('v_c')(PG)或 sp_helptext 'v_c'(SQL Server)逐层展开,手动拼出最终 SQL,再跑一次 EXPLAIN —— 如果这时能命中索引、rows 显著下降,那问题就锁定在嵌套层级导致的下推失败。
字段表达式和 SELECT * 破坏下推能力
视图里写 UPPER(name) 或 SELECT *,会让优化器无法确认列的来源和可过滤性:
-
WHERE UPPER(name) = 'ABC'无法命中name索引(除非建函数索引) -
SELECT *导致中间结果集膨胀,网络传输、内存占用、排序开销都变大 - 即使基表有
(tenant_id, status)索引,但视图里ORDER BY UPPER(name),也可能触发Using filesort
真正起作用的永远是基表索引——视图不存数据,也不建索引。所谓“视图走索引”,本质是外层条件能否被下推、基表能否复用已有索引。字段顺序错一位、表达式裹一层、嵌套深一层,下推就可能失败。










