视图中子查询每次引用都会触发完整重解析,因其仅存select文本,需内联展开并重新经历语法解析、语义绑定、统计估算与执行计划生成全过程。

视图定义不执行,但每次引用都会触发完整重解析
视图本身不存储数据,也不缓存执行计划;它只是保存的一段 SELECT 文本。当外部查询(比如 SELECT * FROM v_user_summary WHERE status = 'active')引用该视图时,SQL Server 或 MySQL 优化器会把整个视图定义“内联展开”——也就是把子查询原样塞进外层查询的 AST 中,再从头做语法解析、语义绑定、统计信息读取、执行计划生成。这意味着:哪怕视图里只有一个 (SELECT COUNT(*) FROM orders WHERE user_id = users.id),只要被调用一次,这个子查询逻辑就参与一次完整解析链路。
相关子查询导致解析与优化无法提前收敛
如果子查询是相关的(即引用了外层表字段),优化器就无法把它当作独立单元预处理。例如:SELECT u.name, (SELECT MAX(o.amount) FROM orders o WHERE o.user_id = u.id) FROM users u。这里 MAX(o.amount) 的执行依赖于每行 u.id,优化器不能提前算出一个固定值,也无法为子查询单独生成稳定计划——它必须保留嵌套结构,反复校验内外表连接语义、索引可用性、参数敏感性。这直接拖慢解析阶段,尤其在高并发场景下,大量并发查询同时尝试构建相似但参数不同的执行树,CPU 在解析器层就打满。
嵌套层级加深会让优化器放弃代价估算
三层以上子查询(比如视图 A 引用视图 B,B 里又有子查询 C)极易触发优化器的“超时退化”行为。SQL Server 默认对复杂查询启用 QUERY_OPTIMIZER_HOTFIXES 限制,MySQL 则有 optimizer_search_depth 阈值(默认为 62)。一旦嵌套过深或组合路径爆炸,优化器可能跳过完整搜索,直接选一个次优计划(比如强制嵌套循环而非哈希连接),甚至拒绝缓存该计划。此时你看到的不只是慢,而是同一语句有时快、有时慢——因为解析阶段已不稳定。
子查询干扰统计信息推导和参数嗅探
优化器依赖列分布、基数估计来决策是否下推谓词、是否重排 JOIN 顺序。但子查询(尤其是含聚合或标量函数的)会切断原始表统计信息的传递路径。例如:WHERE u.id IN (SELECT user_id FROM logins WHERE login_time > GETDATE() - 1),优化器无法准确估计子查询返回多少个 user_id,只能按默认选择率(如 10%)估算,进而错误判断是否该走索引查找还是扫描。更麻烦的是,SQL Server 的参数嗅探机制在遇到子查询时经常失效,导致第一次执行用的计划被复用到后续不同数据分布的请求上。
视图里的子查询不是“写一次、跑一次”,而是每次调用都重新经历解析、绑定、估算、生成四步——最隐蔽的负担不在运行时扫描,而在还没开始扫描前,CPU 就已在解析器里反复推演逻辑关系。











