【问题标题】:Execute stored procedure that has parameters with sp_executesql执行带有 sp_executesql 参数的存储过程
【发布时间】:2016-07-26 15:41:39
【问题描述】:

我有一个带有参数的简单存储过程

CREATE Procedure GetSupplierForTesting
    (@SupplierId INT)
AS
    SELECT SuppLabel 
    FROM Supplier 
    WHERE Supplier.SupplierId = @SupplierId

我可以在像这样的另一个存储过程中使用 exec 命令调用它

exec GetSupplierForTesting @SupplierId = 10

我看到一篇文章解释了sp_executesql 如何比exec 快。我的问题是我不知道如何调用带有sp_executesql 参数的存储过程。我试过这段代码

DECLARE @SupplierId INT = 10;
EXEC sp_executesql N'GetSupplierForTesting', N'@SupplierId INT', @SupplierId

但我收到一个错误:

过程或函数“GetSupplierForTesting”需要参数“@SupplierId”,但未提供该参数

【问题讨论】:

  • 总是 如果可能,使用EXEC spName 运行存储过程,性能指标仅与EXECEXEC <SQL string here> 用法有关 - 即,如果您构建了 SQL 语句到一个字符串中,或​​者你在一个变量中有一个过程名称。
  • 还要注意在sp_executesql之前你仍然有'EXEC',因为你正在调用那个存储过程。
  • 您能否将文章链接添加到您的问题中,听起来在任何情况下 sp_executesql 都不太可能是执行过程的更快方式。
  • @JamesZ msdn.microsoft.com/en-us/library/ms175170.aspx,但正如 Martin Smith 解释的那样,只有将 SQL 语句构建到字符串中才会更快
  • 是的,这篇文章只意味着查询计划的重用——并且只适用于动态 SQL

标签: sql-server stored-procedures


【解决方案1】:

你需要的语法是

DECLARE @SupplierId INT = 10;

EXEC sys.sp_executesql N'GetSupplierForTesting @SupplierId=@SupplierId', 
                       N'@SupplierId INT', 
                         @SupplierId=@SupplierId

但是不要这样做。这是完全没有意义的。使用sp_executesql 基本上包装相同的exec 语句并在不同的范围内执行它并没有预期的神奇性能提升。

随便用

exec dbo.GetSupplierForTesting @SupplierId = 10

【讨论】:

  • 可悲的是这种“错误”@SupplierId=@SupplierId 没有错误/警告信息
【解决方案2】:

1

性能问题基于以下假设:当您使用非参数化即席查询时,它(表示此查询的字符串)每次都会不同 - 因为特定的参数值是查询文本的一部分。

虽然参数化查询保持它的主体不变,因为你有where ... and title = @title 代替where ... and title="asdf"。只有变量@title 的内容会改变。但是查询文本仍然存在,sql server 意识到不需要重新编译它。

每次更改其中使用的值时,都会重新编译非参数化查询。

2

您遇到异常是因为您的脚本没有将任何参数传递给存储的过程。

您的脚本是:'GetSupplierForTesting' - 就是这样。

通过将参数传递给sp_executesql,您将它们传递给scipt。不是脚本中使用的 sp,而是脚本本身。例如:

exec sp_executesql N'print @val', N'@val int', @val = 1

这个脚本确实使用了变量@val。你的 - 没有。它只包含过程的名称。所以你的脚本更正应该看起来像

exec sp_executesql
    N'exec GetSupplierForTesting @Supplier = @Supplier_id_value', 
    N'@Supplier_id_value int',
    @Supplier_id_value = 10
  1. 脚本包含调用您的 sp 的代码,此代码将参数传递给 sp,其值取自 @Supplier_id_value 变量
  2. @Supplier_id_value 被声明为该脚本内部的 int
  3. 10 的值被传递给 脚本的参数

3

您所说的性能问题是关于 ad-hoc,而不是 SP。

这个问题的另一面是参数嗅探问题。有时对于特定的参数值,您的脚本或 SP 应该使用另一个执行计划,不同于它用于先前传递的参数值的计划。

每次重新编译(“缓慢执行”)ad-hoc 肯定会(重新)编译并且可能会获得更好的执行计划,而 SP 或参数化查询可能不会重新编译并使用更糟糕的是,不是最优的执行计划,并且最终会比“由于重新编译而变慢”的临时查询慢得多。

在 sql 中没有“写这个——它会运行缓慢”、“写那个——它会像火箭一样飞驰”的规则。这一切都取决于许多因素。有时可能需要专门的 ad-hoc,有时 - 应该完全避免它们。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    • 2014-03-03
    • 2023-04-07
    • 2019-02-16
    相关资源
    最近更新 更多