with recompile 只能在 create/alter procedure 中定义,不能用于 exec;单次重编译应使用 option (recompile);过程级 with recompile 开销大,仅适用于极少数参数值极端稀有且执行路径完全不同的场景。

WITH RECOMPILE 不是加在 EXEC 后面的命令
很多人误以为 EXEC uspMyProc @p1 = 1 WITH RECOMPILE 是给存储过程“动态开启重编译”,其实这是错的——WITH RECOMPILE 只在 CREATE PROCEDURE 或 ALTER PROCEDURE 语句中作为定义选项生效,不能在 EXEC 时临时追加(SQL Server 会直接报错:Incorrect syntax near the keyword 'WITH')。真想单次绕过缓存计划,得用 EXEC uspMyProc @p1 = 1 OPTION (RECOMPILE),但注意这是语句级提示,不是过程级。
CREATE PROCEDURE 时加 WITH RECOMPILE 的真实代价
写成 CREATE PROCEDURE uspReport @date DATE WITH RECOMPILE AS ... 意味着每次调用都丢弃旧计划、从头解析+优化+生成执行计划。这不是“提速”,而是主动放弃 SQL Server 最核心的计划复用机制:
- 高并发下多个会话同时触发编译,
sys.dm_exec_query_stats中total_worker_time猛涨,CPU 使用率飙升 - 容易引发编译锁阻塞:
waitresource显示OBJECT: dbid:object_id [[COMPILE]],大量会话卡在LCK_M_X - 只适用于极少数场景:BI 工具动态传列名 + 任意时间范围,且每天调用不超过几次
真正该用 OPTION (RECOMPILE) 而不是 WITH RECOMPILE 的地方
多数所谓“参数嗅探问题”其实只需要局部重编译。比如过程里有一句查询对参数极度敏感,其余逻辑稳定:
SELECT * FROM Orders WHERE OrderDate >= @from AND OrderDate —— 只重编译这句,变量值被当常量参与优化(@from 直接走索引查找)- 它能规避
Parameter Compiled Value和实际值严重偏离的问题,而不会拖累整个过程其他语句 - 比过程级
WITH RECOMPILE开销小一个数量级,也更容易定位和测试
先确认是不是真需要重编译,而不是统计信息过期
盲目加重编译前,必须验证根因:
- 查是否已多次重编译:
SELECT plan_generation_num, execution_count FROM sys.dm_exec_query_stats qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st WHERE st.text LIKE '%uspMyProc%'——plan_generation_num > 1仅说明发生过重编译,不等于该加WITH RECOMPILE - 开
SET STATISTICS XML ON执行一次,看执行计划里Parameter Compiled Value是否和传入值严重不匹配(比如编译时是@status = 'Active',运行时却是'Cancelled') - 用
DBCC SHOW_STATISTICS('Orders', 'IX_OrderDate')检查Modification Counter是否远超Rows Sampled * 0.2,过期统计信息才是更常见元凶
真正要动手加 WITH RECOMPILE 的情况极少:只有当某几个参数值极端稀有(如占比 0.02%)、又必须走完全不同的执行路径,且无法用 OPTIMIZE FOR (@p UNKNOWN) 或拆分逻辑解决时,才考虑它。绝大多数时候,修统计信息或加语句级 OPTION (RECOMPILE) 更安全、更有效。










