我最近在工作中被要求执行许多SQL Server存储过程“改编”。我可以管理,但我主要是.Net开发人员所以我不知道什么是好的做法,或者是否有更好的方法来做事。
简而言之,就是这种情况。我们有许多脚本每晚运行,以避免对生产产生任何影响。它们扫描多个数据库(链接服务器和所有数据库)以查找特殊情况,并在发现这种情况时添加记录。每个脚本在所有数据库(具有数百万条记录)上执行该操作,并且有超过一百个以这种方式运行的脚本。
现在,我被要求更改这些脚本,以便他们可以接受参数并被称为“按需”(不再是夜间运行)。容易。
我犹豫不决的是,他们希望调用SAME过程但是针对不同的场景,每个场景都会传递它自己的一组参数,然后根据我的理解,查询应该执行一些业务逻辑为特定的“场景”执行。
例如,存储过程将定义这些输入参数:
@PersonId, @OrderId, @OrderType, @RequestCode, ....
可能还有一些。
当存储过程收到@PersonId
时,我应该返回该人的所有特殊情况,但如果是@OrderType
,则应该是针对该特定类型的所有情况。但是,如果它收到OrderId
,则存储过程应返回该订单的所有特殊情况。如果提供了RequestCode
,它应该为每个人返回与该代码相关联的所有需求的所有情况。有4个场景需要处理,所有这些场景应该返回相同的数据,但是针对不同的情况。
他们特别要求应该只有一个脚本(每种特殊情况)来处理所有可能性。
就像我说的那样,现在脚本每晚运行,整个数据库都没有参数。
我建议将脚本转换为代码,这样我就可以使用所有好的模式,添加测试,隔离它们以及所有内容。如果我保持“sql方式”,我担心每一个小小的改变都意味着更多的测试,因为我们可以轻松访问程序员,但DBA是如此罕见,在特定情况下按需检测到.NET(无论如何都会调用检测请求......),具有一些类和接口应该更容易维护和发展,即使对于大三学生来说也是如此。
请求不再在每条记录上运行,并且没有那么多员工会提出这些请求,特别是那些请求不会同时发生。所以我也没有看到性能问题?
我是开发人员,所以当然我偏见。但是,如果有一种很好的方式来做他们对我的要求(将所有内容保存在存储过程中,包含许多参数,条件和显然某种程度的业务逻辑),我对此也不错。
对于这篇长篇文章感到抱歉,非常感谢所有人,尤其是那些有时间提供一些建议的人!
编辑:让我说我调整脚本来处理所有可能性,您可以预见的对测试,可维护性的主要影响是什么?由于我没有经验,我认为,对于这样一个“神奇的脚本而不是可以做的一切”,调试,测试和一切都将是一场噩梦,但这里的人们似乎忽略了它。但是他们不是程序员,也不是DBA,因此我想提出一些可以敲响钟声的原因,让他们以正确的方式做事,无论是现在还是未来,即使这意味着最初会有更高的成本。谢谢!
答案 0 :(得分:0)
您在问题中添加了很多细节,但是,如果您询问如何处理存储过程中的可选参数,那么一种方法是在where子句评估中包含缺少值。如果参数用于过滤数据,则此流程将起作用。我将警告,Mode
,ProcessingType
,Action
,UpdateType
或Operation
参数类型通常表示半透明操作。
要考虑的另一件事是查询优化器如何处理参数。如果使用类似的参数集多次调用存储过程,则优化器可以选择适合第一个或最常用参数集的查询计划。稍后,您可以传递一个值,该值是缓存计划的最坏情况。这可能会导致您的“亚秒级”存储过程无法在很长一段时间内开始搅拌。您可以通过优化和编译器提示来解决这个问题,但是,我建议您阅读参数嗅探,以便在您开始从存储过程中看到奇怪的性能时做好准备。
CREATE PROCEDURE MySPWithOptionalParams
(@P1 INT = NULL,
@P2 INT = NULL,
@P3 INT = NULL)
AS
SELECT *
FROM MyTable
WHERE (@P1 IS NULL OR F1 = @P1)
AND (@P2 IS NULL OR F2 = @P2)
AND (@P3 IS NULL OR F3 = @P3)
答案 1 :(得分:0)
拥有一个可以做完全不同的事情的单个存储过程是一个非常糟糕的设计。这就像在dotnet中创建一个方法,根据传递的参数做一些完全不同的方法。就像你的编程代码一样,你希望你的程序做一件事并做得很好。
这归结为性能。将为存储过程创建执行计划并将其存储在缓存中。当你有这样的多个执行路径时,它完全破坏了引擎生成有效执行计划的能力。因此,即使该计划对于一组参数来说很好,但对另一组参数来说这将是可怕的。但它将使用已存在于缓存中的计划(如果存在)。如果有的话,您可以创建一个过程作为“驱动程序”,并让它根据参数调用各种其他过程。这为每条路径提供了一个好的计划。