OPTION (RECOMPILE) 并非修复而是跳过参数嗅探,将当前参数值作为常量生成专属执行计划且不缓存;适用于参数分布差异大、单次编译开销远小于执行开销的低频场景,如报表查询,但会失效统计信息更新等自动重编译机制。

OPTION (RECOMPILE) 怎么绕过参数嗅探
它不是“修复”参数嗅探,而是直接跳过嗅探环节:SQL Server 在编译带 OPTION (RECOMPILE) 的语句时,会把当前传入的参数值当作已知常量参与优化,生成一个**完全匹配本次参数**的执行计划,并且不缓存该计划。下一次执行时再走一遍完整编译流程,用新参数重新估算、选算子、定路径。
哪些场景加了就见效,哪些反而更慢
生效的前提是:性能瓶颈真由参数分布差异引发,且单次编译开销远小于执行开销。否则可能越加越卡。
- 适合:
@date范围从 1 天跳到 5 年、@status值在 0.1% 和 95% 行之间切换、报表类低频调用 - 不适合:高频 OLTP 接口(如每秒几十次)、语句本身含大量 JOIN 或复杂子查询(编译耗时 > 执行耗时)、WHERE 中混有固定过滤条件(如
AND is_deleted = 0)削弱了参数主导性 - 典型误用:
CREATE PROCEDURE ... WITH RECOMPILE—— 整个过程每次调都重编译,连 SELECT COUNT(1) 都要重走解析 → 绑定 → 优化全流程
为什么不能全局加在存储过程开头
OPTION (RECOMPILE) 是语句级提示,只作用于紧邻的 SELECT/INSERT/UPDATE/DELETE 语句。加在过程定义头部或 EXEC 调用时,SQL Server 根本不识别——它只会报错或静默忽略。
- 正确写法:
SELECT * FROM orders WHERE order_date >= @from OPTION (RECOMPILE); - 错误写法:
CREATE PROC uspGetOrders @from DATE OPTION (RECOMPILE) AS ...(语法错误) - 错误写法:
EXEC uspGetOrders '2025-01-01' OPTION (RECOMPILE)(无效,OPTION不支持出现在 EXEC 后)
比 RECOMPILE 更轻、更稳的替代动作
如果只是想让优化器“别盯死第一次的值”,用局部变量往往比加提示更自然、副作用更小。
- 把
WHERE status = @status改成DECLARE @status_local INT = @status; WHERE status = @status_local; - 效果等同于
OPTION (OPTIMIZE FOR UNKNOWN):优化器失去参数真实值,退回到统计直方图平均密度估算 - 注意:变量类型必须严格一致(比如
@status是INT,就不能声明成VARCHAR(10),否则触发隐式转换,索引失效) - 局限:对极端倾斜数据(如 99%/1%)不如
RECOMPILE精准,但胜在稳定、无编译压力
真正容易被忽略的是:加了 OPTION (RECOMPILE) 后,该语句就彻底脱离计划缓存体系——统计信息更新、索引重建这些本可触发自动重编译的机制,对它完全失效。你得自己判断:这个语句是否真的需要“每次都新鲜出炉”,还是只要“别被第一次带偏”就够了。

















