我有一个带参数
的简单存储过程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',未提供
答案 0 :(得分:6)
您需要的语法是
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
答案 1 :(得分:2)
性能问题基于以下假设:当您使用非参数化即席查询时,它(表示此查询的字符串)每次都会不同 - 因为特定参数值是查询文本的一部分。
虽然参数化查询保持身体不变,因为代替where ... and title="asdf"
你有where ... and title = @title
。只有变量@title
的内容发生变化。但是查询文本仍然存在,并且sql server意识到不需要重新编译它。
每次更改其中使用的值时,都会重新编译非参数化查询。
您将获得异常,因为您的脚本未将任何参数传递给存储过程。
您的脚本是:'GetSupplierForTesting'
- 就是这样。
通过将参数传递给sp_executesql
,您将它们传递给scipt。不是脚本中使用的sp,而是脚本本身。 E.g:
exec sp_executesql N'print @val', N'@val int', @val = 1
此脚本确实使用变量@val。你的 - 没有。它只包含proc的名称。因此,您的脚本更正应该是
exec sp_executesql
N'exec GetSupplierForTesting @Supplier = @Supplier_id_value',
N'@Supplier_id_value int',
@Supplier_id_value = 10
@Supplier_id_value
变量@Supplier_id_value
被声明为此脚本内部的int 10
的值传递给脚本的参数 您正在谈论的性能问题是关于ad-hocs,而不是SP。
此问题的另一面是参数嗅探问题。有时使用特定的参数值,您的脚本或SP应使用另一个执行计划,与之前传递的参数值的计划不同。
每次重新编译("慢慢执行")ad-hoc将被(重新)编译以确保并且可能会获得更好的执行计划,而SP或参数化查询可能不会被重新编译并将使用更糟糕,更不理想的执行计划,并且由于重新编译而最终执行速度会慢得多,并且#34;临时查询。
没有"写这个 - 它会慢慢地工作","写下 - 它会像火箭一样发作#34; sql中的规则。这一切都取决于很多因素。有时人们可能需要专门的ad-hocs,有时候 - 应该完全避免它们。