SQL Server 2022 的参数敏感计划(PSP)自动启用,仅对参数值分布极不均匀且谓词基数影响大的查询生效,如 CustomerID 高度倾斜或 OrderDate 跨度大;最多评估前三个敏感谓词;需统计信息准确、兼容级别≥160且未使用 OPTIMIZE FOR UNKNOWN 或 RECOMPILE。

SQL Server 2022 的参数敏感计划(PSP)不是开关,而是自动启用的优化能力;只要满足条件,存储过程无需改代码就能为不同参数值匹配更优执行计划——但前提是别手动关掉它。
哪些存储过程能自动触发参数敏感计划?
PSP 不是所有查询都适用,它只对“参数值分布极不均匀 + 谓词基数影响大”的场景生效。典型如:
-
WHERE CustomerID = @cid,而CustomerID列直方图显示:95% 行集中在 'ALL' 和 'ARCHIVED',其余几百个值各占 0.01% -
AND OrderDate > @from_date,且@from_date可能是“昨天”或“三年前”,导致估算行数差几个数量级 - 同一存储过程中多个谓词都敏感时,PSP 最多只评估前三个(由统计信息直方图边界决定)
验证是否命中 PSP:查 sys.dm_exec_procedure_stats,同一 object_id 出现多个不同 plan_handle,且 query_plan 中包含 <ParameterSensitivePlan> 标签,即为生效。
为什么加了 OPTIMIZE FOR UNKNOWN 反而禁用了 PSP?
OPTIMIZE FOR UNKNOWN 的语义是“完全忽略参数值,纯靠统计信息平均估算”,这与 PSP 的设计目标冲突——PSP 正是要利用运行时参数值做精准基数判断并路由到不同变体。一旦用了这个提示,优化器就跳过 PSP 调度逻辑,退化为单计划缓存。
- 错误写法:
WHERE StatusID = @sid OPTION (OPTIMIZE FOR (@sid UNKNOWN)) - 正确替代:删掉该提示,确保统计信息更新(
UPDATE STATISTICS Orders WITH FULLSCAN),让 PSP 自动识别直方图偏斜 - 若必须控制首次编译行为,改用
OPTIMIZE FOR (@sid = 'Active')—— 这不干扰 PSP,只是帮第一次生成一个更典型的调度器表达式
RECOMPILE 是 PSP 的替代方案吗?
不是。两者解决路径完全不同:OPTION (RECOMPILE) 每次都抛弃缓存、全量重优化,CPU 开销高,适合极低频或参数跨度极端的个别语句;PSP 是轻量级复用——共享一个调度器计划,按参数值自动选已编译好的查询变体,无额外编译成本。
- 高频 OLTP 存储过程(如每秒调用 50+ 次)加
RECOMPILE,可能让 CPU 使用率飙升 30% 以上,而 PSP 几乎无感知 - 若存储过程里混用
RECOMPILE和 PSP 敏感谓词,SQL Server 会直接忽略 PSP,只走重编译路径 - 真正需要 PSP 却没生效?先检查是否启用了
QUERY_OPTIMIZER_HOTFIXES(默认开启),以及数据库兼容级别是否 ≥ 160(SQL Server 2022)
容易被忽略的底层依赖
PSP 看似“自动”,但实际高度依赖统计信息质量与列分布表达能力。最常踩的坑是:
- 直方图过时:哪怕只差 5% 的数据变更,若
ModificationCounter未触发自动更新,PSP 就可能把“稀疏值”误判为“均匀分布”,导致不生成变体 - 复合索引列顺序不当:例如
INDEX IX_Status_Date ON Orders(StatusID, OrderDate),但 PSP 主要感知StatusID,而OrderDate的分布差异被掩盖 - 临时表或表变量参与谓词:PSP 只作用于基表列,
#tmp.StatusID或@t.StatusID不会被识别为敏感参数源
上线前务必用真实参数组合跑几轮,观察 sys.dm_exec_cached_plans 中是否出现多个 plan_handle 对应同一存储过程——这才是 PSP 在后台真正工作的证据。

















