结论:不应盲目使用with recompile,它并非性能开关而是高成本兜底手段;应优先排查统计信息、参数嗅探和执行计划复用问题,并通过系统视图、执行计划及干扰项检查确认是否真需重编译。

直接结论:不要盲目加 WITH RECOMPILE,它不是性能开关,而是高成本兜底手段;绝大多数“慢”问题应先查统计信息、参数嗅探和执行计划复用状态。
怎么确认真需要重编译,而不是误判了问题?
先别动代码,用系统视图验证是否真发生了有害重编译:
- 查
sys.dm_exec_query_stats:运行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') - 检查干扰项:
SET ARITHABORT是否一致;用DBCC SHOW_STATISTICS('Orders', 'IX_OrderDate')看Modification Counter是否远超Rows Sampled * 0.2;确认没在过程里拼EXEC(@sql) WITH RECOMPILE
WITH RECOMPILE 的三种写法,成本和效果完全不同
写错位置,等于主动放弃性能:
-
创建时加:
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,而是OPTION (RECOMPILE);它只重编译这一条语句,还能把变量当常量优化(比如@id直接走索引查找),比过程级更精准、开销更低
为什么滥用 WITH RECOMPILE 会让性能更差?
每次执行都丢弃旧计划、从头硬解析,相当于废掉了 SQL Server 最核心的计划复用机制:
- 高并发下多个会话同时触发编译,
sys.dm_exec_query_stats中total_worker_time显著增长,CPU 利用率飙升 -
WITH RECOMPILE对EXEC无效,只对CREATE PROCEDURE或ALTER PROCEDURE定义生效;想在运行时控制单条语句,必须用OPTION (RECOMPILE) - 若过程内含临时表或未完全限定对象名(如不写
dbo.uspMyProc而只写uspMyProc),还可能引发编译锁阻塞(waitresource显示为OBJECT: dbid:object_id [[COMPILE]])
真正难处理的是参数分布极端不均、统计信息滞后又无法及时更新、或查询逻辑本身高度依赖运行时值的场景——这些地方才值得考虑 OPTION (RECOMPILE),而 WITH RECOMPILE 几乎不该出现在新代码里。










