存储过程修改后未生效,大概率是sql server复用了缓存中的旧执行计划;alter procedure不自动清除计划缓存,需手动执行dbcc freeproccache或sp_recompile触发重编译。

存储过程修改后没生效,大概率不是代码写错了,而是 SQL Server 还在用旧的执行计划——它缓存在 sys.dm_exec_cached_plans 里,没被刷新。
为什么改了存储过程,执行结果还是老样子
SQL Server 编译并缓存存储过程的执行计划,后续调用会直接复用。即使你用 ALTER PROCEDURE 修改了逻辑,只要原计划还在缓存中,SQL Server 就不会重新编译,而是继续走旧路径。尤其当参数、数据分布或统计信息没变时,优化器更倾向“偷懒”复用。
- 现象:执行
ALTER PROCEDURE后立刻CALL,返回结果与修改前一致 - 原因:缓存中的 plan_handle 仍指向旧计划,
ALTER不自动触发缓存清理 - 验证方式:查
sys.dm_exec_procedure_stats,看last_execution_time和cached_time是否滞后于你修改的时间
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'):它也会清计划缓存,但范围更大(含资源池、元数据等),副作用更不可控
生产环境执行前必须确认的三件事
这个命令会让后续首次执行变慢,还可能引发瞬时 CPU 尖峰——因为所有语句都要重新编译。不能拍脑袋运行。
- 确认当前负载低:避开业务高峰,检查
sys.dm_exec_requests是否有大量活动会话 - 确认权限足够:需要
ALTER SERVER STATE权限,普通db_owner不行 - 确认不是唯一解:优先尝试
sp_recompile 'proc_name',它只标记存储过程为“需重编译”,下次调用时才编译,更温和
容易被忽略的兼容性细节
Azure SQL Database 和 SQL Server 2016+ 支持 WITH NO_INFOMSGS 抑制日志输出,但旧版本不识别该选项;另外,sql_handle 在 sys.dm_exec_query_stats 中可查,但它对应的是“语句级”缓存项,不是整个存储过程——想精准清除一个存储过程的所有缓存计划,得用 plan_handle 或靠 pool_name(如果用了 Resource Governor)。
最稳妥的做法永远是:改完存储过程 → 查 sys.dm_exec_cached_plans 确认旧计划还在 → 手动清除 → 再验证。别依赖“改完就生效”的直觉。











