sql server 2022存储过程执行计划优化核心是适配新机制而非改语法,因tempdb争抢gam/sgam页导致pagelatch_up等待陡增,需满足版本≥16.0.1000.6、重启、tempdb文件数匹配逻辑cpu数且大小一致;参数敏感计划(psp)未生效常因optimize for unknown或recompile禁用;优化前提始终是统计信息新鲜。

SQL Server 2022 存储过程执行计划优化,核心不是“怎么写新语法”,而是让旧代码自动适配新机制——尤其当你的存储过程已经上线多年、不能轻易加 RECOMPILE 或改参数逻辑时。
为什么升级到2022后执行计划还是卡在tempdb?
现象是存储过程执行延迟抖动、PAGELATCH_UP 等待陡增,但错误日志里没报错。本质是本地临时表(#tmp)、表变量(@table)或行版本控制(如启用了 READ_COMMITTED_SNAPSHOT)持续争抢 tempdb 的 GAM/SGAM 页。
SQL Server 2022 的并发 GAM/SGAM 更新机制默认启用,但必须满足两个前提:
- 实例版本 ≥
16.0.1000.6,且已重启(仅安装补丁不生效) - tempdb 文件数需匹配逻辑 CPU 数(例如 8 核 → 至少 8 个数据文件),且各文件大小、增长设置一致;单文件配置下新机制完全无法触发
- 验证方式:运行
SELECT * FROM sys.dm_os_wait_stats WHERE wait_type LIKE 'PAGELATCH%',对比升级前后PAGELATCH_UP累计等待时间是否下降 30% 以上
参数敏感计划(PSP)为什么没生效?
同一存储过程对不同参数值仍复用同一个低效计划,比如 @CustomerID = 'ALL' 该走扫描却硬套查找计划——这不是 PSP 失效,而是你主动关掉了它。
-
OPTIMIZE FOR UNKNOWN会强制优化器放弃参数感知,直接禁用 PSP;只要存在这个提示,PSP 就不会参与计划选择 -
WITH RECOMPILE或语句级OPTION (RECOMPILE)同样绕过 PSP,因为每次都是全新编译,不进计划缓存,也就没有“多计划并存”可选 - 检查是否真有多个计划:执行
SELECT p.*, q.query_plan FROM sys.dm_exec_procedure_stats p CROSS APPLY sys.dm_exec_query_plan(p.plan_handle) q WHERE object_id = OBJECT_ID('YourProc'),结果中plan_handle不应全相同
OPTION (RECOMPILE) 该不该加在存储过程里?
加了不一定快,反而可能更慢——它解决的是“计划错配”,不是“计划本身差”。高频 OLTP 场景下滥用,CPU 压力和编译开销会盖过执行收益。
- 适合加:参数取值跨度极大(如
@id从 1 到 500 万)、WHERE 条件几乎全依赖该参数、且统计信息无法覆盖分布差异 - 不适合加:WHERE 中含固定过滤(如
AND Status = 1),或参数分布均匀(如@region只有 5 个固定值),此时 PSP 或OPTIMIZE FOR更轻量 - 替代方案优先级:先跑
DBCC SHOW_STATISTICS看直方图是否过时 → 再考虑OPTIMIZE FOR (@pid = 5000)→ 最后才评估RECOMPILE
查询存储里的优化重播脚本能省多少编译时间?
它不是“跳过编译”,而是复用上次优化过程中关键路径的决策快照(OptimizationReplay),对复杂查询(多表 JOIN、嵌套子查询、大量谓词)效果明显,但有硬性门槛。
- 只对
StatementOptmLevel="FULL"的完全优化计划生效;带RECOMPILE提示的语句、分布式查询、未启用查询存储的数据库,一律不生成重播脚本 - 是否保留取决于运行时实测:如果重放脚本节省的编译时间 > 存储它带来的内存开销,才会留在缓存中;否则异步丢弃
- 验证方式:查
sys.query_store_plan表,看is_optimization_replay_enabled是否为 1,再比对同一查询多次执行的last_compile_duration_ms
最常被忽略的一点:所有这些机制都依赖统计信息新鲜度。哪怕开了 PSP、启用了查询存储、tempdb 配置完美,只要 UPDATE STATISTICS 没跑过,优化器估算的行数就严重失真,计划再“智能”也选不准。别只盯着版本和配置,先确认 sys.dm_db_stats_properties 里关键列的 modification_counter 是否远超阈值。











