位置:首页 > SQL > SQL存储过程执行计划如何重新编译与刷新

SQL存储过程执行计划如何重新编译与刷新

时间:2026-08-14  |  作者:白桃企划师  |  阅读:0

结论很明确:WITH RECOMPILE 不能拿来随手就开,它不是所谓的“性能开关”,而是一种代价不低的兜底方案。

更稳妥的做法,是先把统计信息、参数嗅探以及执行计划复用这些常见问题查清楚。

再结合系统视图、执行计划和各类干扰项逐一确认,最后再判断是否真的需要重编译。

如何重新编译SQL存储过程执行计划?

直接结论:不要盲目加 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,放在新代码里,基本上就不太合适了。

免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多