with recompile 是诊断或兜底工具,非提速手段;滥用会导致每次执行都硬解析,cpu飙升、性能恶化,仅适用于逻辑极不稳定、参数分布极端不可预测或临时救火三类场景,且须配合监控验证。

WITH RECOMPILE 不是提速手段,而是诊断或兜底工具;滥用它会让 CPU 翻倍、性能雪上加霜。
为什么 WITH RECOMPILE 会让 CPU 暴涨
每次执行都丢弃旧计划、从头编译,等于把“预编译”优势全废掉。尤其在高并发场景下,多个会话同时触发硬解析,sys.dm_exec_query_stats 里 plan_generation_num 会飙升,total_worker_time 显著增长。
常见误用场景:
- 看到“参数嗅探导致慢”,第一反应加
WITH RECOMPILE—— 实际应优先用OPTIMIZE FOR - 把
WITH RECOMPILE当成“刷新缓存”的快捷键,却没意识到它不解决统计信息过期、索引缺失等根因 - 在调用链路中层层叠加(如 A 调 B,B 带
WITH RECOMPILE),编译开销呈指数放大
什么情况下才该用 WITH RECOMPILE
仅限以下三类真实场景,且必须配合监控验证:
- 存储过程逻辑极不稳定:比如内部动态拼接了大量条件,且无法改写为
sp_executesql参数化形式 - 参数值分布极端且不可预测:例如
@date_from可能是昨天,也可能是五年前,且业务不允许拆分过程或加OPTIMIZE FOR UNKNOWN - 临时性救火:已确认是首次编译时参数失准(如第一次传了空值),又不能立刻改代码上线,才用它绕过当前批次的计划缓存
注意:WITH RECOMPILE 对 EXEC 无效,只对 CREATE PROCEDURE 或 ALTER PROCEDURE 定义生效;运行时加 OPTION (RECOMPILE) 是另一回事,别混用。
替代方案比 WITH RECOMPILE 更有效
真正提升效率,靠的是让 SQL Server 复用高质量计划,而不是放弃复用:
- 用
OPTIMIZE FOR (@p = 'Active')替代无差别重编译,锁定典型值生成稳定计划 - 把多分支逻辑(
IF @mode = 'A'/ELSE IF @mode = 'B')拆成独立小过程,避免单个计划强行适配所有路径 - 检查并更新统计信息:
DBCC SHOW_STATISTICS('Orders', 'IX_OrderDate')看Modification Counter是否远超Rows Sampled * 0.2 - 统一
SET选项:确保调用方和过程内都设SET ARITHABORT ON,否则计划根本不会复用
如果连 sys.dm_exec_query_stats 都查不到该过程的记录,说明它压根没进缓存——这时候加 WITH RECOMPILE 只是在给错误归因打掩护。
容易被忽略的兼容性细节
WITH RECOMPILE 在本机编译存储过程中不支持,会直接报错 Msg 12317;SQL Server 2016+ 的查询存储(Query Store)也无法捕获带该选项的过程的计划变更历史,因为每次都是全新生成。
更隐蔽的问题是:如果过程里用了表变量(@tmp TABLE),而数据量超过 100 行,SQL Server 会默认按 1 行估算,此时即使加 WITH RECOMPILE 也救不了执行计划质量——得换临时表或加 OPTION (RECOMPILE) 在具体语句级控制。










