2

我读过在存储过程中使用动态 SQL 会损害存储过程的性能。我猜这个理论是存储过程不会存储通过 EXEC 或 sp_executesql 执行的 SQL 的执行计划。

我想知道这是不是真的。如果是真的,我是否对多个嵌套的 IF 块有同样的问题,每个块都有不同的 SQL 语句“版本”?

4

2 回答 2

7

如果您有多个嵌套的 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 将无法存储执行计划

于 2012-11-07T00:03:35.767 回答
3

这就是 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 查询优化器可能会重用它为第一次执行生成的执行计划

http://msdn.microsoft.com/en-us/library/ms188001.aspx

于 2012-11-06T21:46:04.610 回答