使用 sp_executesql 时,为什么更改参数化样式会导致计划缓存中的计划降低?

var*_*ble -2 sql-server plan-cache

通常 sp_execute sql 将重用缓存的计划,其中 EXEC 将为每个参数创建新计划。

在此示例中,两个查询都使用 sp_executesql - 第二个查询导致计划缓存中的计划数量较少的原因是什么?

查询1:

在此输入图像描述 在此输入图像描述

查询2:

在此输入图像描述 在此输入图像描述

von*_*ryz 6

exec这与vs 的关系不大,sp_executesql而与您的查询构建关系不大。

第一个查询实际上生成 100 个不同的查询,如下所示,

select foo from bar where param=1 # Query hash abc123
select foo from bar where param=2 # Query hash def456
select foo from bar where param=3 # Query hash efg789
...
select foo from bar where param=100 # Query hash zzz999
Run Code Online (Sandbox Code Playgroud)

正如您所指出的,这些将最终出现在计划缓存中。第二个查询生成一个参数化查询,如下所示,

select foo from bar where param=@p # Query hash opq789
Run Code Online (Sandbox Code Playgroud)

因此,第二件事是使用不同的参数值运行相同的查询,并且查询哈希保持不变。就像这样,

select foo from bar where param=@p # Query hash opq789, @p=1
select foo from bar where param=@p # Query hash opq789, @p=2
select foo from bar where param=@p # Query hash opq789, @p=3
...
select foo from bar where param=@p # Query hash opq789, @p=100
Run Code Online (Sandbox Code Playgroud)

根据经验,除非必要,否则不要使用。 exec很容易出现 SQL 注入。

编辑:根据您获得多个计划的原因。SQL Server 计算查询的哈希值,用于查找是否已提交相同的查询以及计划缓存中是否有可重用的计划。

当查询使用硬编码值(例如param=1等)时param=2,每个查询将获得不同的哈希值(除非发生冲突,但这与此处无关)。不同的哈希意味着 SQL Server 认为它以前没有见过该查询,因此它创建并缓存它(除非针对临时工作负载设置进行优化,其中仅缓存第一次执行的计划存根)。有强制参数化,可以用来强制参数成为参数而不是硬编码值。

当查询使用参数(例如 )时param=@value,查询哈希不包含将传入 的任何值@value。因此,每当使用不同的参数值重新运行相同的查询时,它将使用相同的计划(除非查询优化器注意到该计划不再有效或计划缓存已被清除。)