SQL Server 存储过程修改后未生效,主因是执行计划缓存未刷新;ALTER PROCEDURE 不清除旧计划,SQL Server 仍复用缓存中的老逻辑,需手动执行 DBCC FREEPROCCACHE 或 sp_recompile 才能生效。

SQL Server 存储过程修改后没生效,大概率不是代码写错了,而是执行计划缓存没刷新——ALTER PROCEDURE 不会自动清掉旧计划,SQL Server 仍复用缓存里的老逻辑。
为什么 ALTER PROCEDURE 后调用还是旧结果
SQL Server 编译存储过程后,会把执行计划缓存在 sys.dm_exec_cached_plans 中。后续 CALL 或 EXEC 都直接复用这个计划,哪怕你已用 ALTER PROCEDURE 改了源码。只要缓存没被踢出,就永远走旧路径。
- 验证方法:查
sys.dm_exec_procedure_stats,对比last_execution_time和你修改时间,若明显滞后,说明在跑旧计划 - 典型现象:
CALL返回结果、影响行数、甚至报错信息都和修改前一致 - 参数或统计信息没变时,优化器更倾向“偷懒”复用,不会主动重编译
DBCC FREEPROCCACHE 清什么、不清什么
DBCC FREEPROCCACHE 只清执行计划缓存(即编译后的查询计划),不碰数据页、不删统计信息、也不重置 sys.dm_exec_procedure_stats 里的执行计数。
- 清全部:直接运行
DBCC FREEPROCCACHE,影响所有数据库所有缓存计划——生产环境慎用 - 清单个:先从
sys.dm_exec_cached_plans查出目标plan_handle,再执行DBCC FREEPROCCACHE (plan_handle) - 别误用
DBCC FREESYSTEMCACHE ('ALL'):它清得更广(含资源池、元数据等),副作用不可控
比 DBCC 更温和的替代方案
优先用 sp_recompile 标记存储过程为“需重编译”,下次调用时才真正编译,对性能冲击小得多。
- 执行
EXEC sp_recompile 'your_procedure_name'即可 - 它只更新
sys.objects的is_ms_shipped和相关标志位,不强制刷缓存 - 适合生产环境日常维护,尤其当你不确定是否所有调用方都已重启连接时
- 注意:对 Azure SQL Database 和 SQL Server 2016+ 有效;旧版本需确认兼容性
容易被忽略的跨版本/跨平台细节
不同环境处理方式差异大,硬套同一套流程容易踩坑:
- MySQL 不支持
ALTER PROCEDURE刷新逻辑,必须DROP PROCEDURE+CREATE PROCEDURE才生效 - Azure SQL Database 和 SQL Server 2016+ 支持
WITH NO_INFOMSGS抑制DBCC FREEPROCCACHE输出,旧版本会报错 -
sql_handle在sys.dm_exec_query_stats中对应的是语句级缓存项,不是整个存储过程——想精准清除一个 SP 的所有计划,得靠plan_handle或pool_name(如果启用了 Resource Governor) - ORM 框架(如 Entity Framework)可能缓存了存储过程元数据,改完 SP 后不重启 AppDomain 或不清
SqlCacheDependency,照样返回旧结果
最稳妥的闭环动作永远是:改完 ALTER PROCEDURE → 查 sys.dm_exec_cached_plans 确认旧计划还在 → 手动清除或标记重编译 → 再验证。别依赖“改完就生效”的直觉——这在 SQL Server 里从来不是默认行为。

















