SQL Server 2019升级后自动重编译是正常行为,主因是版本升级清空过程缓存、启用新基数估算器及查询优化器改进,导致旧执行计划不可复用;需结合回归测试验证新计划性能。

升级到 SQL Server 2019 后,存储过程不一定“必须”重新编译,但大概率会触发自动重编译——这不是 bug,而是引擎对执行计划兼容性与优化策略更新的主动响应。
SQL Server 2019 升级后为什么会自动重编译?
SQL Server 在版本升级时会清空整个过程缓存(sys.dm_exec_cached_plans 中相关条目被移除),这是最直接的原因。此外,2019 引入了新的查询优化器行为(如批次模式在行存储上的启用、新 Cardinality Estimator 版本默认启用),旧执行计划无法复用或不再安全。
-
sp_recompile不是唯一触发方式;服务重启、数据库脱机/上线、DBCC FREEPROCCACHE都会清空缓存,升级过程几乎必然包含其中一环 - 即使没清缓存,SQL Server 也会在首次调用时检测到版本不匹配(
compatibility_level或query_optimizer_hotfixes状态变化),强制生成新计划 - 统计信息自动更新阈值在 2019 中略有调整(尤其对大表),也可能间接触发重编译
哪些存储过程最容易出问题?
不是所有过程都会表现异常,但以下几类在升级后更常出现性能抖动或错误:
- 依赖临时表(
#temp)或表变量(@table)的过程:2019 对临时对象统计信息推导逻辑有改进,旧计划可能误判行数 - 使用
OPTION (RECOMPILE)或WITH RECOMPILE的过程:这类过程本就每次执行都编译,升级后只是延续行为,但要注意参数嗅探逻辑是否因新 CE 改变 - 引用已弃用功能的过程:比如
SET ARITHABORT OFF+ 参数化查询组合,在 2019 兼容模式下可能因 SET 选项敏感度提升导致计划不重用 - 涉及 CLR 或外部访问(如
OPENROWSET)的过程:升级后权限模型或元数据验证更严格,首次执行可能报错而非静默失败
怎么判断某个过程是否已重编译?
不能只看“有没有报错”,要查执行计划是否刷新:
- 运行
SELECT * FROM sys.dm_exec_procedure_stats WHERE object_id = OBJECT_ID('usp_GetCustomerOrders'),对比last_execution_time和cached_time—— 如果两者接近,说明刚重编译过 - 执行
DBCC SHOW_STATISTICS('Orders', '_WA_Sys_00000002_00000000')查看统计信息Updated时间,若在升级后更新过,可能已触发关联过程重编译 - 开启扩展事件捕获
query_post_compilation_showplan,观察目标过程是否在升级后首次调用时产生新 plan
要不要手动执行 sp_recompile?
通常不需要,但有例外:
- 升级后发现某过程性能明显下降(比如从 200ms 涨到 2s),且确认其执行计划未更新(
cached_time还是升级前时间),这时可显式执行EXEC sp_recompile 'usp_GetCustomerOrders' - 批量处理场景下,为避免上线后首次调用集中重编译造成延迟毛刺,可在维护窗口内提前执行
sp_recompile,让计划“预热” - 注意:
sp_recompile只标记失效,不立即编译;真正编译发生在下次执行时,所以它不能替代真实负载测试
真正容易被忽略的是:重编译本身不保证性能更好——新计划可能因新 CE 误估基数而选错连接方式。升级后必须用生产级数据做回归测试,不能只依赖“自动重编译”就认为万事大吉。











