视图不支持参数,无法实现执行计划缓存与复用;其本质是SQL文本内联展开,每次查询均整体编译,而存储过程因具备参数签名,可基于类型匹配复用计划。
视图本身不支持参数,执行计划无法按参数值做差异化缓存——它每次都是“无参展开”,而存储过程天然带参数签名,优化器能基于参数统计信息生成并复用适配的计划。
视图只是保存的 SELECT 语句文本,数据库在查询时会把它内联(inline)到外部 SQL 中,再整体编译。整个过程不经过“参数绑定 → 计划缓存查找 → 复用或重编译”的流程。所谓“执行计划重用”,是针对带参数的对象(如存储过程、参数化 Ad-hoc 查询)设计的机制,视图不在这个体系里。
SELECT * FROM user_active_view WHERE dept_id = 5,SQL Server 实际编译的是整条展开后的 SQL,不是“调用视图 + 传参”WHERE dept_id = 5 和 WHERE dept_id = 999,只要外部查询文本不同(字面量不同),就可能触发两次编译(除非开启自动参数化且满足条件)@dept_id 这类参数,语法上就不允许存储过程在创建时就固化了参数名、类型和顺序,比如 CREATE PROC get_users_by_dept @dept_id INT。优化器把 @dept_id 当作一个“变量占位符”,编译一次后,后续所有对该过程的调用,只要参数类型一致,就尝试复用该计划(即使实际值差异很大,这就是 parameter sniffing 的根源)。
WITH RECOMPILE 或在调用时加 OPTION(RECOMPILE) 控制重编译时机真需要参数驱动的复用逻辑,必须跳出视图,改用真正支持参数的对象:
CREATE FUNCTION dbo.users_by_dept(@dept_id INT) RETURNS TABLE),它可嵌入 FROM 子句,且支持计划缓存RETURNS TABLE 的 SQL 函数,配合 STABLE 声明,优化器能下推谓词、复用计划PREPARE/EXECUTE 模拟WHERE 字句试图“模拟参数”,那只会让外层过滤失效,引发全表扫描最常被忽略的一点:视图的“复用”是逻辑复用,不是执行计划复用。你省了写 JOIN 的功夫,但没省数据库的计算开销——每次查,都重新跑一遍底层 SELECT。如果基表大、JOIN 多、计算重,性能瓶颈就藏在这里,而不是参数没缓存。