with recompile不是性能优化开关,而是极少数参数分布极端失衡时的兜底手段;多数情况应更新统计信息或用option(recompile)精准优化单语句。

WITH RECOMPILE 不是性能优化开关,而是兜底手段
加 WITH RECOMPILE 不会让存储过程“变快”,反而大概率让 CPU 暴涨、执行更慢。它只在极少数参数分布极端失衡(比如 @status = 'Cancelled' 仅占 0.02% 行但必须走嵌套循环)且无法用统计信息、OPTIMIZE FOR 或逻辑拆分解决时才考虑。多数情况下,真正该做的是更新统计信息:UPDATE STATISTICS dbo.Orders WITH FULLSCAN,或检查直方图是否过期(DBCC SHOW_STATISTICS('Orders', 'IX_OrderDate') 中 Modification Counter 远大于 Rows Sampled * 0.2 就是信号)。
三种写法成本差异极大,选错等于自废武功
同一关键词,位置不同,影响天差地别:
-
CREATE PROCEDURE uspReport @date DATE WITH RECOMPILE AS ...:每次调用都全量重编译,仅适用于 BI 工具动态传列名 + 任意时间范围、且每天调用不到几次的场景 -
EXEC uspReport '2025-04-01' WITH RECOMPILE:只影响这一次执行,适合 DBA 手动救急(比如某次卡死),绝不能写进应用代码 -
SELECT * FROM Orders WHERE OrderDate >= @from OPTION (RECOMPILE):注意这不是WITH RECOMPILE,而是语句级重编译;它只重编译这一条语句,还能把变量当常量优化(如@id直接走索引查找),开销远低于过程级
怎么判断真该用,而不是误判参数嗅探?
盲目加 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说明已多次重编译,但不等于该加 - 确认是不是参数嗅探失准:过程开头加
SET STATISTICS XML ON,执行一次,看执行计划里Parameter Compiled Value和实际传入值是否严重偏离(比如编译时用@status = 'Active',调用时传了'Cancelled') - 排除干扰项:检查
SET ARITHABORT是否一致;确认没在过程里拼EXEC(@sql);确保没混用不同 SET 选项导致计划无法复用
OPTION (RECOMPILE) 比 WITH RECOMPILE 更精准、更轻量
当过程里只有某一条语句受参数影响严重(比如小数据量该走查找、大数据量该走扫描),而其余逻辑稳定,就该用 OPTION (RECOMPILE) 而不是整个过程加 WITH RECOMPILE。它不会影响其他语句的计划复用,还能让优化器把变量当字面量处理(例如 @id = 123 直接参与索引选择),这是 WITH RECOMPILE 做不到的。但注意:高频 OLTP 场景(每秒几十次调用)下,哪怕单语句加 OPTION (RECOMPILE) 也会明显推高 CPU,此时应优先考虑 OPTIMIZE FOR (@pid = 5000) 或拆分分支逻辑。










