根本原因是参数嗅探导致缓存计划错配当前参数的数据分布;表现为同一存储过程不同参数性能差异巨大,如100ms突增至15s,且执行计划误选全表扫描而非索引查找。

根本原因不是执行计划“突然失效”,而是 SQL Server 缓存的计划不再适配当前参数的实际数据分布——典型表现是同一存储过程,换一组参数就从 100ms 拉长到 15s,且 DBCC SHOWPLAN 显示本该走索引查找却走了全表扫描。
怎么确认是参数嗅探导致的执行计划错配
别靠感觉,用系统视图交叉验证:
- 查当前卡住的请求:
SELECT session_id, total_elapsed_time, statement_text FROM sys.dm_exec_requests CROSS APPLY sys.dm_exec_sql_text(sql_handle) WHERE total_elapsed_time > 5000 - 查历史平均耗时异常的语句:
SELECT t.text, qs.avg_elapsed_time FROM sys.dm_exec_query_stats qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t WHERE t.text LIKE '%YourProcName%' AND qs.avg_elapsed_time > 10000000 - 关键佐证:执行
EXEC YourProcName @param = 'typical_value' WITH RECOMPILE后立刻变快 → 基本锁定是缓存计划错配
三种重编译方式选哪个、怎么加
粒度越细,副作用越小。优先按以下顺序尝试:
-
OPTION (RECOMPILE)加在具体慢语句后(如 SELECT 或 UPDATE 行末):适合参数跨度极大(如时间范围从 1 天到 3 年)、且该语句是性能瓶颈点。每次执行都重优化,CPU 开销略升,但计划绝对匹配当前参数 -
OPTION (OPTIMIZE FOR UNKNOWN)加在同位置:让优化器忽略真实参数值,纯按统计信息平均分布估算。比 RECOMPILE 轻量,适合参数频繁变化但无极端倾斜的场景 -
WITH RECOMPILE加在存储过程定义末尾(CREATE PROC ... AS ... WITH RECOMPILE):整个过程每次调用都重编译。仅用于低频调用、逻辑简单、参数组合完全不可预测的 SP;高频 OLTP 场景下易引发 CPU 瓶颈
为什么 ALTER PROCEDURE 能“临时救急”
因为 ALTER PROCEDURE 会强制清除该过程在计划缓存中的所有已编译版本,下次调用必须重新生成计划——这相当于手动触发一次重编译,但属于“治标不治本”的操作:
- 它不解决参数分布问题,只清掉旧计划;如果下次传入的仍是非典型参数,新缓存的计划可能又错
- 它影响所有并发调用,期间可能出现短暂编译争用
- 真正要稳定,得在语句级加
OPTION (RECOMPILE)或改用局部变量绕过嗅探(如DECLARE @local_date = @input_date; WHERE date_col = @local_date)
最容易被忽略的一点:重编译只是应对参数嗅探的手段,不是万能加速器。如果统计信息严重过期(sys.dm_db_stats_properties 中 last_updated 是几周前),即使加了 RECOMPILE,优化器也还是“瞎估”——先跑 UPDATE STATISTICS,再考虑加提示。











