【问题标题】:Dynamic SQL and stored procedure optimization动态 SQL 和存储过程优化
【发布时间】:2012-10-26 22:14:03
【问题描述】:

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

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

【问题讨论】:

    标签: sql-server sql-server-2008 stored-procedures dynamic-sql


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 我正在考虑的情况是使用动态 SQL 来确定在我的 SELECT 中使用哪种 where 子句。 AFAIK,我无法参数化我的查询,因为我没有将参数用作字段值。或者有没有办法参数化 where 子句?
      • 不,我不认为 where 子句可以参数化,因为 where 子句是 SQL 命令的一部分。听起来您的动态 SQL 本质上是静态的,但它只是有不同的风格。我想你只是想减少代码重复。我想唯一可以确定的方法是加速测试这两种样式,但在你的情况下,我预计差异可以忽略不计。
      • @DeanOC 为什么在执行级别使用 Name = Value 方法(例如 statement = sqlcommand 等)?这不仍然是相同的 exec sp_executesql sqlcommand, paramList, Param1, Param2 您所指的正确构建动态 SQL,其中 params 不是硬编码的,这里就是这种情况。只是好奇!
      • 没有任何区别;这只是个人喜好。我发现如果我明确使用@param = value 而不仅仅是枚举值,我会犯更少的错误。如果您愿意,请随意使用快捷方式。
      猜你喜欢
      • 2018-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-06
      相关资源
      最近更新 更多