SQL Server 2022的智能查询处理(IQP)对存储过程开箱即用但非全自动,需满足统计信息及时、参数化谓词、兼容级别≥160、启用PARAMETER_SENSITIVE_PLAN等条件;PSP最多作用于前三个高风险谓词,验证需查query_store_plan中ParameterSensitivePlan与QueryVariant标识。

SQL Server 2022 的智能查询处理(IQP)对存储过程是开箱即用的,但**不会自动生效于所有场景**——它依赖统计信息质量、参数化行为、查询结构和数据库级开关配置。盲目启用或忽略细节反而可能引入计划缓存膨胀或变体选择偏差。
参数敏感计划(PSP)是否自动作用于存储过程
是,但有前提:存储过程中的查询必须满足参数敏感性判定条件,且数据库启用了 PARAMETER_SENSITIVE_PLAN(默认关闭)。SQL Server 不会因为它是 CREATE PROCEDURE 就特殊对待;它只看内部 T-SQL 是否含参数化谓词、列直方图是否显示非均匀分布。
- 必须使用参数(如
@StatusID),不能拼接字符串或用局部变量绕过参数嗅探检测 - 对应列(如
StatusID)需有更新及时的统计信息,且直方图桶(steps)中存在明显倾斜(例如某值占 95% 行数) - 数据库兼容级别必须 ≥ 160(即 SQL Server 2022),且未显式禁用 IQP:
ALTER DATABASE SCOPED CONFIGURATION SET PARAMETER_SENSITIVE_PLAN = ON; - 同一查询中最多只对前三个谓词启用 PSP,优先选高风险谓词(如
WHERE StatusID = @x AND CreatedDate > @y中可能只选StatusID)
如何验证存储过程是否生成了多个查询变体
不能只看 sys.dm_exec_query_stats 或 SSMS 执行计划窗口——它们只显示当前缓存的“调度计划”(scheduler plan),不直接暴露变体。要确认 PSP 实际起效,得查底层元数据:
- 执行存储过程几次,传入明显不同分布的参数值(如
@StatusID = 1vs@StatusID = 99) - 运行:
SELECT qsp.query_id, qsp.plan_id, qsp.is_forced_plan, qsp.count_compiles, qsp.avg_compile_duration_ms, CAST(qsp.query_plan AS XML) AS query_plan_xml FROM sys.query_store_plan qsp JOIN sys.query_store_query qsq ON qsp.query_id = qsq.query_id WHERE qsq.object_id = OBJECT_ID('dbo.GetOrdersByStatus'); - 在返回的
query_plan_xml中搜索ParameterSensitivePlan和QueryVariant字样;若存在多个plan_id且count_compiles > 1,说明已生成变体 - 注意:若启用了查询存储但未设为
READ_WRITE模式,这些记录不会持久化
OPTION (RECOMPILE) 与 PSP 的冲突关系
二者互斥:OPTION (RECOMPILE) 会完全跳过计划缓存,自然也绕过了 PSP 的调度逻辑。PSP 的价值恰恰在于「复用+分叉」——既避免每次重编译开销,又解决单计划低效问题。
- 已有
OPTION (RECOMPILE)的存储过程,PSP 不起作用;迁移时需先移除该提示 - 若业务要求强一致性(如报表导出必须用最新统计),
RECOMPILE仍更可控;PSP 是面向 OLTP 高频、低延迟场景的折中方案 - 混合使用危险:
WHERE StatusID = @x OPTION (RECOMPILE)会导致 PSP 谓词识别失败,整个查询退出 PSP 流程 - 替代方案:用
OPTIMIZE FOR (@x = UNKNOWN)保留缓存,但失去 PSP 的自适应能力
自动索引建议对存储过程的实际影响
自动索引(CREATE_INDEX = ON)不区分调用来源,只要它观察到存储过程内某查询反复触发全表扫描 + 高逻辑读,就可能生成索引建议。但关键点在于:
- 建议基于历史执行统计,不是实时分析;首次运行存储过程不会立刻触发建议
- 若存储过程含动态 SQL(
EXEC(@sql)),其内部语句可能无法被自动索引模块捕获——因为解析发生在运行时,且无稳定对象引用 - 生成的索引名形如
auto_created_index_..._on_dbo_Orders,不带业务语义;上线前必须人工审核列顺序、包含列、是否唯一等 - 黑名单机制有效:
EXEC sp_automatic_tuning_set_blacklist @schema_name='dbo', @table_name='Orders', @object_type='TABLE';可阻止对核心表的自动干预
PSP 和自动索引都不是“设完就跑”的黑盒功能——它们依赖统计信息鲜度、查询写法规范、以及足够多的真实负载样本。最常被忽略的是:在测试环境开启 PSP 后,不主动用不同参数值触发多次执行,就误以为“没生效”。实际中,一个变体可能要等三次符合基数范围的调用才会落地缓存。

















