SQL Server存储过程对性能的影响

时间:2018-06-18 04:54:31

标签: sql sql-server stored-procedures

我想编写可用于多用途的存储过程。任何人都可以帮助我找到从这些方法在SQL Server中编写存储过程的最佳实践吗?每个人的绩效影响是什么?

方法1: 参数@KEY,@ VALUE

IF @KEY = 'ISACTIVE'
BEGIN 
    SELECT ID, STATECODE, STATENAME, ISACTIVE 
    FROM STATE 
    WHERE ISACTIVE = @VALUE
END
ELSE IF @KEY = 'STATECODE'
BEGIN
    SELECT ID, STATECODE, STATENAME, ISACTIVE 
    FROM STATE  
    WHERE STATECODE = @VALUE
END
ELSE
BEGIN
    SELECT ID, STATECODE, STATENAME, ISACTIVE 
    FROM STATE
END

方法:2 参数@ISACTIVE,@ STATECODE

SELECT ID, STATECODE, STATENAME, ISACTIVE 
FROM STATE
WHERE ISACTIVE = ISNULL(@ISACTIVE, ISACTIVE) 
  AND STATECODE = ISNULL(@STATECODE,STATECODE)

方法:3

参数@KEY,@ VALUE

DECLARE @SQLQRY NVARCHAR(500)
SET @SQLQRY = 'SELECT ID, STATECODE, STATENAME, ISACTIVE FROM STATE WHERE ' + @KEY +' = ' + @VALUE
EXEC @SQLQRY

哪种方法在性能和可重用性方面是最好的方法?

或者还有其他选择来实现这个目标吗?

3 个答案:

答案 0 :(得分:0)

我肯定会选择方法2 ,这在我看来既可维护也可永久。

方法1 中,您正在复制代码,因此维护明智,这不是最好的方法。

在使用动态SQL查询的方法3 中,它不是最好的方法,因为它不提供智能感知支持,也限制了SQL服务器的优化能力表现。

如果您遇到任何性能问题,请考虑在“ISACTIVE”和“STATECODE”列上引入索引。还要分析查询执行计划,并在需要时使用分析器进行进一步调查。

答案 1 :(得分:0)

  

我想编写可用于多用途的存储过程。

考虑到这种愿望(尽管我对此需求有所顾虑), 取决于

  • 方法1:随着业务规则变得复杂,您将开始重复大量代码。当你意识到,你有多个重复选择,可能有几个连接或EXISTS子句,也许还有另一个程序员必须修改某些东西忘记编辑其中一个查询。当您开始同时应用多个过滤器时(例如SELECT其中IsActive = 0 AND StateCode = 'AR'),事情变得更加复杂。根据您要过滤的密钥,此方法可以更轻松地返回不同的结果集。
  • Aproach 2:您可以将过滤器叠加在一起,您只需要编写SELECT一次,但如果您有很多行并且过滤器适用于不同的行表。另一个问题是您可能必须为比较的两端提供替换值:如果我们只想选择NULLStateCode的记录,那么您将需要执行ISNULL(StateCode, 'SomeImpossibleStateCode') = ISNULL(@StateCode, 'SomeImpossibleStateCode')之类的过滤器{1}}或类似(@StateCode IS NULL AND StateCode IS NULL) OR (@StateCode = StateCode)
  • 方法3:由于它是动态的,维护起来比较困难,依赖的表/列不会显示在sysdepends等视图上,您​​可能需要采取其他措施防止SQL注入。但是,它提供了完全避免条件过滤器的灵活性,这将使您的查询更简单,更高效。您甚至可以将表作为输入参数接收,其中包括要应用的过滤器,链接它们的逻辑运算符(ANDOR)和过滤器优先级。

结论:

  • 如果您的牌表不大且您可能搜索的键数量较少,接近2 将是最好的,但您必须测试效果。

  • 方法3 似乎最适合处理所有方案,包括性能。

  • 我肯定会避免接近1 ,因为它很容易出现维护错误。如果您觉得不同的密钥需要返回不同的列或应用不同的查询条件,那么是时候将您的全部SP拆分为不同的。

答案 2 :(得分:0)

必须阅读:Dynamic Search Conditions in T‑SQL作者:Erland Sommarskog。因为方法2很糟糕,但可以成为最好的。

以下是链接文章的简短摘要。

从性能的角度来看,

方法1 是好的。 Optimiser可以生成良好的计划并使用索引(如果可用)。 这里的问题是查询的可能变体/排列的数量。如果你有三个参数Key1,Key2,Key3它将成为一个相当丑陋的嵌套IF三级深度。如果添加更多参数,从维护的角度来看,这将变得不切实际。

从维护的角度来看,

方法2 是好的,但是从性能的观点来看,“按原样”是坏的。即使ISACTIVE = ISNULL(@ISACTIVE, ISACTIVE)为NULL,也会评估@ISACTIVE,并可能阻止有效使用索引。

查询应该像这样重写:

SELECT ID, STATECODE, STATENAME, ISACTIVE 
FROM STATE
WHERE
    (ISACTIVE = @ISACTIVE OR @ISACTIVE IS NULL) 
    AND (STATECODE = @STATECODE OR @STATECODE IS NULL)
OPTION(RECOMPILE);

OPTION(RECOMPILE)非常重要。从本质上讲,它允许优化器将参数的实际值内联到查询中,简化逻辑表达式并生成计划,这与方法1或更好的方法一样好。有关详细信息,请参阅文章。

方法3 将产生良好的计划,如方法1中所示,尽管不是方法2中的最佳方案。虽然动态SQL有困难但维护也不错。如果你走这条路,你应该阅读Erland The Curse and Blessings of Dynamic SQL的另一篇文章。