我想编写可用于多用途的存储过程。任何人都可以帮助我找到从这些方法在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
哪种方法在性能和可重用性方面是最好的方法?
或者还有其他选择来实现这个目标吗?
答案 0 :(得分:0)
我肯定会选择方法2 ,这在我看来既可维护也可永久。
在方法1 中,您正在复制代码,因此维护明智,这不是最好的方法。
在使用动态SQL查询的方法3 中,它不是最好的方法,因为它不提供智能感知支持,也限制了SQL服务器的优化能力表现。
如果您遇到任何性能问题,请考虑在“ISACTIVE”和“STATECODE”列上引入索引。还要分析查询执行计划,并在需要时使用分析器进行进一步调查。
答案 1 :(得分:0)
我想编写可用于多用途的存储过程。
考虑到这种愿望(尽管我对此需求有所顾虑), 取决于 。
EXISTS
子句,也许还有另一个程序员必须修改某些东西忘记编辑其中一个查询。当您开始同时应用多个过滤器时(例如SELECT
其中IsActive = 0 AND StateCode = 'AR'
),事情变得更加复杂。根据您要过滤的密钥,此方法可以更轻松地返回不同的结果集。SELECT
一次,但如果您有很多行并且过滤器适用于不同的行表。另一个问题是您可能必须为比较的两端提供替换值:如果我们只想选择NULL
上StateCode
的记录,那么您将需要执行ISNULL(StateCode, 'SomeImpossibleStateCode') = ISNULL(@StateCode, 'SomeImpossibleStateCode')
之类的过滤器{1}}或类似(@StateCode IS NULL AND StateCode IS NULL) OR (@StateCode = StateCode)
。sysdepends
等视图上,您可能需要采取其他措施防止SQL注入。但是,它提供了完全避免条件过滤器的灵活性,这将使您的查询更简单,更高效。您甚至可以将表作为输入参数接收,其中包括要应用的过滤器,链接它们的逻辑运算符(AND
或OR
)和过滤器优先级。结论:
如果您的牌表不大且您可能搜索的键数量较少,接近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的另一篇文章。