在SQL Server中,查询计划何时会包含<ParameterList>标签?
<ParameterList>标签? 刚好之前研究过这个问题,我来给你理清楚:SQL Server查询计划里的<ParameterList>标签,只有在查询被真正参数化(不管是自动、强制还是显式操作)的时候才会出现。你提到的用DECLARE+SET定义变量的场景,不属于参数化查询范畴,所以计划里不会有这个标签。
下面具体分几种情况说明:
1. 自动参数化(Simple Parameterization)
SQL Server会自动对一些结构简单的查询做参数化处理,比如:
SELECT * FROM a WHERE ID > 1;
第一次执行后,SQL Server会把它转换为参数化版本:
SELECT * FROM a WHERE ID > @p0;
此时缓存的查询计划里就会出现<ParameterList>,里面会记录参数@p0的数据类型、预估取值等信息。
划重点:自动参数化只适用于规则内的简单查询,带JOIN、子查询、聚合逻辑的复杂查询一般不会触发自动参数化。
2. 强制参数化(Forced Parameterization)
如果你的数据库开启了强制参数化(执行ALTER DATABASE [你的库名] SET PARAMETERIZATION FORCED;),那么绝大多数查询都会被强制参数化,不管复杂度高低。这种情况下,哪怕是原本不会被自动参数化的查询,其缓存计划里也会包含<ParameterList>。
3. 显式参数化执行(使用sp_executesql)
当你用sp_executesql显式传递参数执行查询时,比如:
DECLARE @p1 INT = 1; EXEC sp_executesql N'SELECT * FROM a WHERE ID > @p1', N'@p1 INT', @p1 = @p1;
这种场景下,查询计划必然会包含<ParameterList>——因为你明确告诉SQL Server这是一个可重用的参数化查询,它会生成通用计划来适配不同的参数值。
为什么你的例子里没有<ParameterList>?
你用DECLARE+SET定义变量后直接执行查询的方式,本质是批处理执行,而非参数化查询。SQL Server会把整个批处理(变量声明、赋值、查询)当作一个整体编译,编译时变量的取值是确定的(会用这个值做基数估计),所以计划不需要<ParameterList>——这个计划就是针对当前变量值生成的,并不是为了重复执行不同参数值设计的。
总结一下:只有当SQL Server把查询处理成「可以用不同参数值重复执行的通用计划」时,才会在计划里加入<ParameterList>来记录参数的相关信息。
内容的提问来源于stack exchange,提问作者ldoroni

