【发布时间】:2012-10-26 22:14:03
【问题描述】:
我了解到在存储过程中使用动态 SQL 会损害存储过程的性能。我猜这个理论是存储过程不会存储通过 EXEC 或 sp_executesql 执行的 SQL 的执行计划。
我想知道这是不是真的。如果是真的,我是否对多个嵌套的 IF 块有同样的问题,每个块都有不同的 SQL 语句“版本”?
【问题讨论】:
标签: sql-server sql-server-2008 stored-procedures dynamic-sql
我了解到在存储过程中使用动态 SQL 会损害存储过程的性能。我猜这个理论是存储过程不会存储通过 EXEC 或 sp_executesql 执行的 SQL 的执行计划。
我想知道这是不是真的。如果是真的,我是否对多个嵌套的 IF 块有同样的问题,每个块都有不同的 SQL 语句“版本”?
【问题讨论】:
标签: sql-server sql-server-2008 stored-procedures dynamic-sql
这就是 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 查询优化器很可能重用 它为第一次执行生成的执行计划。
【讨论】:
如果您有多个嵌套的 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 将无法存储执行计划
【讨论】:
@param = value 而不仅仅是枚举值,我会犯更少的错误。如果您愿意,请随意使用快捷方式。