SQL Server中ALTER PROCEDURE不刷新执行计划缓存,需手动清除:查sys.dm_exec_cached_plans获plan_handle后执行DBCC FREEPROCCACHE(plan_handle),或用sp_recompile标记重编译;MySQL则因元数据锁和定义窗口可能导致“改了未生效”,需检查会话及依赖更新。

改完存储过程,执行结果还是老样子,不是代码没写对,而是数据库还在用缓存的旧执行计划。
SQL Server:ALTER PROCEDURE 不清缓存,得手动干预
SQL Server 编译后会把执行计划缓存在 sys.dm_exec_cached_plans 里,ALTER PROCEDURE 只更新定义,不碰缓存。下次调用仍走旧路径,尤其当参数、统计信息没变时,优化器几乎必然复用。
- 验证是否真没刷新:查
sys.dm_exec_procedure_stats,对比last_execution_time和你执行ALTER的时间戳 - 精准清除单个过程:先从
sys.dm_exec_cached_plans找到对应plan_handle,再执行DBCC FREEPROCCACHE (plan_handle) - 更温和的替代方案:执行
sp_recompile 'proc_name',它只标记“下次调用需重编译”,不强制全量刷新,适合生产环境 - 别用
DBCC FREESYSTEMCACHE ('ALL')——它清的不只是计划,还可能波及资源池、元数据缓存,副作用难控
MySQL:没有执行计划缓存概念,但元数据锁和定义窗口会骗人
MySQL 不缓存执行计划,但修改过程时会加元数据锁(MDL),且 ALTER PROCEDURE 分三步:删旧定义 → 写新定义 → 刷新缓存。这中间存在极短的“定义缺失窗口”。正在运行的 CALL 若恰好读到这个空窗,就会报 ERROR 1305 (42000): PROCEDURE db_name.proc_name does not exist。
- 现象是“改了但没生效”,实际可能是旧会话已崩,而你没注意到错误日志
- 确认是否有活会话卡在调用中:查
information_schema.processlist,过滤INFO LIKE 'CALL%proc_name%' - 云数据库(如阿里云 RDS)对
mysql.proc表强制只读,任何绕过ALTER直接写表的操作都会导致后续CALL报ERROR 1294 - 安全热更新只能靠命名切换:
RENAME PROCEDURE old_proc TO temp_old+CREATE PROCEDURE new_proc,再让应用逐步切流量
跨平台共性坑:依赖对象没同步更新
你以为只改了一个存储过程?它可能调用了函数、视图或临时表。这些依赖项若未同步更新,旧会话第一次访问时才暴露问题,不是改过程那一刻就报错。
- SQL Server 下,字段重命名后,存储过程仍引用旧名,报“列名无效”——用
sp_refreshsqlmodule 'proc_name'重新解析依赖 - MySQL 没等价命令,必须显式
ALTER PROCEDURE或DROP+CREATE,否则逻辑不会更新 - ORM 层(如 Entity Framework)常缓存存储过程元数据,改完 SP 后不重启 AppDomain 或不清
SqlCacheDependency,也会继续返回旧结果 - 参数类型变更(如
@id INT→@id BIGINT)引发隐式转换,导致索引失效——查执行计划里有没有CONVERT_IMPLICIT
最易被忽略的是:缓存清理本身有代价。在 SQL Server 上执行 DBCC FREEPROCCACHE 会让所有语句首次执行变慢,并可能触发瞬时 CPU 尖峰;在 MySQL 上强行 KILL 正在调用的会话,可能中断业务事务。真正稳妥的做法,是改完 → 查缓存状态 → 按需清除 → 立即验证,而不是默认“改了就生效”。











