我已经读过在存储过程中使用动态SQL会损害存储过程的性能。我想理论是存储过程不会存储通过EXEC或sp_executesql执行的SQL的执行计划。
我想知道这是否属实。如果是这样,我是否会遇到多个嵌套IF块的相同问题,每个块都有一个与我的SQL语句不同的“版本”?
答案 0 :(得分:6)
如果您有多个嵌套的IF块,那么SQL Server将能够存储执行计划。 我假设IF是直截了当的,例如。 IF @ Parameter1 IS NOT NULL
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文本不会对要使用的paramer值进行硬编码。它们在exec sp_executesql
中单独传递如果你写了旧的动态sqL
set @sqlcommand = N'Select Something from Table where Field1 = ' + @Param1 + ' AND Field2 = ' + @Param2
exec sp_executesql @sqlcommand
然后SQL Server将无法存储执行计划
答案 1 :(得分:3)
这就是MSDN对它的评价。我强调了你问题的相关部分
对于批处理,sp_executesql与EXECUTE具有相同的行为, 名称范围和数据库上下文。 Transact-SQL语句 sp_executesql @stmt参数中的批处理或批处理直到编译 执行sp_executesql语句。 @stmt的内容是 然后编译并执行作为独立于的执行计划 调用sp_executesql的批处理的执行计划。该 sp_executesql批处理不能引用批处理中声明的变量 调用sp_executesql。本地游标或变量 sp_executesql批处理对于调用的批处理不可见 sp_executesql的。数据库上下文的更改仅持续到最后 sp_executesql语句。
可以使用sp_executesql代替存储过程来执行 当参数值发生变化时,Transact-SQL语句多次 声明是唯一的变化。因为Transact-SQL 语句本身保持不变,只有参数值 更改后,SQL Server查询优化器很可能会重用 它为第一次执行生成的执行计划。