我读过在存储过程中使用动态 SQL 会损害存储过程的性能。我猜这个理论是存储过程不会存储通过 EXEC 或 sp_executesql 执行的 SQL 的执行计划。
我想知道这是不是真的。如果是真的,我是否对多个嵌套的 IF 块有同样的问题,每个块都有不同的 SQL 语句“版本”?
我读过在存储过程中使用动态 SQL 会损害存储过程的性能。我猜这个理论是存储过程不会存储通过 EXEC 或 sp_executesql 执行的 SQL 的执行计划。
我想知道这是不是真的。如果是真的,我是否对多个嵌套的 IF 块有同样的问题,每个块都有不同的 SQL 语句“版本”?
如果您有多个嵌套的 IF 块,那么 SQL Server 将能够存储执行计划。我假设 IF 很简单,例如。如果@Parameter1 不为空
SchmitzIT 的回答是正确的,SQL Server 还可以存储动态 SQL 的执行路径。但是,只有正确构建和执行 sql 时,这才是正确的。
通过正确构建,我的意思是显式声明参数并将它们传递给 sp_executesql。例如
declare @Param1 nvarchar(255) = 'foo'
,@Param2 nvarchar(255) = 'bar'
,@sqlcommand nvarchar(max)
,@paramList nvarchar(max)
set @paramList = '@Param1 nvarchar(255), @Param2 nvarchar(255)'
set @sqlcommand = N'Select Something from Table where Field1 = @Param1 AND Field2 = @Param2'
exec sp_executesql @statement = @sqlcommand
,@params = @paramList
,@Param1 = @Param1
,@Param2 = @Param2
如您所见,sqlcommand 文本没有硬编码要使用的参数值。它们在 exec sp_executesql 中单独传递
如果你写了糟糕的旧动态 sql
set @sqlcommand = N'Select Something from Table where Field1 = ' + @Param1 + ' AND Field2 = ' + @Param2
exec sp_executesql @sqlcommand
那么 SQL Server 将无法存储执行计划
这就是 MSDN 不得不说的。我强调了您问题的相关内容
sp_executesql 在批处理、名称范围和数据库上下文方面与 EXECUTE 具有相同的行为。在执行 sp_executesql 语句之前,不会编译 sp_executesql @stmt 参数中的 Transact-SQL 语句或批处理。然后,@stmt 的内容被编译并作为一个执行计划执行,该执行计划与调用 sp_executesql 的批处理的执行计划分开。sp_executesql 批处理不能引用在调用 sp_executesql 的批处理中声明的变量。sp_executesql 批处理中的本地游标或变量对调用 sp_executesql 的批处理不可见。数据库上下文中的更改仅持续到 sp_executesql 语句的末尾。
当语句的参数值更改是唯一的变化时,可以使用 sp_executesql 代替存储过程多次执行 Transact-SQL 语句。因为 Transact-SQL 语句本身保持不变并且只有参数值发生变化,所以 SQL Server 查询优化器可能会重用它为第一次执行生成的执行计划。