PSP对子查询基本无效,仅作用于主查询参数化谓词;子查询性能问题应优先检查外层索引、复合索引设计、改用APPLY或JOIN拉平逻辑。

参数敏感计划优化(PSP)对子查询基本无效,它只作用于主查询的参数化谓词,不穿透到子查询内部。 即使子查询里有 @device_id 或 @start_time,SQL Server 2022 的 PSP 也不会为子查询单独生成变体计划——子查询的执行方式由外层驱动逻辑和索引决定,不是 PSP 的作用域。
为什么 PSP 不处理子查询中的参数
PSP 优化只识别主查询中“直接出现在 WHERE / ON / HAVING 子句里的参数化谓词”,且需满足统计直方图显示显著数据倾斜、谓词可独立评估等条件。子查询(尤其是相关标量子查询)被优化器视为嵌套计算节点,其谓词不参与 PSP 的谓词筛选流程。你看到的 psp_skipped_reason_enum 中的 UnsupportedComparisonType 或 ConjunctThresholdNotMet,往往就源于子查询结构本身被判定为“不可调度”。
相关子查询性能差,该优先检查什么
- 外层表是否走
Index Seek?如果外层是全表扫描,再好的 PSP 也救不了每行都触发一次子查询的开销 - 子查询 WHERE 条件是否落在复合索引最左列?例如
WHERE device_id = @d AND time > @t,必须有(device_id, time)索引,否则@t参数再敏感也没用 - 是否还在用
SELECT (SELECT TOP 1 ...)?换成OUTER APPLY才能让优化器看清关联意图,配合索引才可能稳定命中Index Seek - 子查询返回 NULL 是否导致外层
WHERE过滤失效?PSP 完全不干预语义,只管基数估算
真要让参数影响子查询行为,得换思路
把子查询逻辑“拉平”到主查询层级,才能让 PSP 生效:
- 用
LEFT JOIN替代NOT IN子查询,并把参数谓词移到 JOIN 条件或主 WHERE 中 - 用
CROSS APPLY (SELECT ... WHERE t.id = outer.id AND t.time > @t),把时间参数暴露在 APPLY 的顶层谓词位置 - 若子查询含聚合(如
MAX(time)),改写为窗口函数MAX(time) OVER (PARTITION BY device_id),再配合WHERE过滤,此时 PSP 可能对主过滤谓词生效
复杂点不在 PSP 开关怎么设,而在于你能否一眼看出:那个子查询根本不是参数敏感问题,而是索引缺失或结构误用。PSP 是给主查询“分身”的工具,不是给子查询“续命”的补丁。

















