构建存储过程的最佳实践

Alb*_*nbo 20 sql stored-procedures

作为主要编写c#的开发人员,我在编写c#代码时采用了一些好的做法.当我有时编写存储过程时,我很难将这些实践应用于存储过程代码.

有几次我继承了噩梦存储过程代码,前三层或四层存储过程设置了一些临时表,并且主要是相互调用.没有真正的工作,只有几行代码.然后最后调用"最终"存储过程,一个3000-5000行SQL代码的大怪物.这段代码通常有很多代码味道,如代码重复,复杂的控制流程(又名意大利面条)和一种方法,它可以在彼此之后堆叠太多的东西,没有明确的分离,其中一块工作开始,它的结束(甚至不是作为除数评论).

我还注意到使用了从中间临时表中选择的注释选择语句.可以重新打开选择以进行调试,但需要在任何调用代码期望返回结果集的特定顺序之前将其删除.

显然,我的队友们也分享了我缺乏良好的SQL写作练习.

所以...(这是真正的问题)...编写模块化可维护存储过程的好方法是什么?

我们欢迎自制的做法和书籍/博客的参考.方法以及帮助完成某些任务的工具.

让我们总结一些我没有找到良好实践的领域

  • 模块化和封装(存储过程通过临时表进行通信真的要走了吗?)
    • 在c#中,我使用用访问修饰符修饰的程序集,类和方法来完成此任务.
  • 调试/测试(比修改调试目标更好?)
    • 调试工具?
    • 调试痕迹?
    • 测试夹具?
  • 使用代码结构代码强调代码/逻辑/数据/控制流程
    • 在c#中,我重构并打破了较小的方法,每个方法只执行一个逻辑任务.
  • 代码重复

大多数情况下,我遇到SQL Server作为DBMS,但DBMS不可知的答案或答案指出其他DBMS的功能:在上述情况下的帮助也是受欢迎的.

为了给出一些背景知识:我遇到的大多数大型存储过程都在报告场景中,其基础是从大型表中创建一些汇总值.但是一路上你需要排除一些异常表中的一些值,在一些尚未完成的东西表中添加一些值,与去年相比(你能想象处理产品变更部门的丑陋代码)年间?)等

HLG*_*GEM 14

我写了很多复杂的存储过程.我会考虑最好的做法:

不要在存储过程中使用动态SQl,除非你正在进行一个搜索过程,其中包含许多可能需要或可能不需要的参数(那么它是目前最好的解决方案之一).如果必须在proc中使用动态SQl,则始终具有调试输入参数,并且如果设置了debug参数,则打印创建的SQL语句而不是执行它.这样可以节省数小时的调试时间!

如果您在proc(插入/更新/删除)中执行多个操作查询,请使用Try Cacth块和事务处理.将一个测试参数添加到输入参数中,当它设置为1时,始终回滚整个事务.在回滚测试模式之前,我通常会有一个部分返回我正在影响的表中的值,以确保我认为我对数据库所做的事实上是我所做的.或者您可以按照以下所示进行检查.就像使用@test参数一样,只需在当前注释掉的选项周围输入以下代码(并取消注释它们)即可.

If @test =1
Begin
Select * from table1 where field1 = @myfirstparameter
End
Run Code Online (Sandbox Code Playgroud)

现在,每次测试时都无需通过评论和取消注释.

@test或@debuig应始终设置为默认值0并放在列表的最后.这样添加它们不会破坏proc的现有调用.

考虑为执行插入/更新/删除的proc设置日志记录和/或错误日志记录表.如果在执行时记录表变量中的步骤和/或错误,则在将回滚插入日志记录表后,它们仍然可用.知道复杂过程的哪个部分失败以及错误是什么在以后可能是非常宝贵的.

在可能的情况下,不要嵌套存储过程.如果需要在循环中运行多个记录,请将存储的proc替换为具有表值参数的proc,并将proc设置为以基于集合而非单独的记录方式运行.如果表值参数有一个记录或多个记录,这将起作用.

如果您有一个包含大量子查询或派生表的复杂选择,请考虑使用CTE.重构任何相关子查询或游标以更好地执行基于集合的代码.总是在数据集方面思考而不是一条记录.

在任何可以想象的情况下,不要筑巢.性能损失远远低于任何少量节省的开发时间.并且相信我,嵌套视图不会节省维护时间,当更改需要到视图最远的视图链.

所有存储过程(和其他数据库代码)都应该在源代码管理中.

表变量适用于较小的数据集,但临时表(以#或##而非临时表开头的真实表)可以更好地处理大型数据集中的性能.如果使用临时表,则在不再需要时删除它们.尽量避免使用全局临时表.

学习编写高性能的SQL.编写SQL的效果通常与SQL一样容易,只有在您了解技术后才能执行.如果你编写复杂的存储过程,没有理由不知道哪种技术比其他技术更好.了解如何确保您的查询是可以查询的.避免使用游标,相关子查询,标量函数以及其他逐行运行的东西.


Cad*_*oux 5

通过临时表进行通信有时会产生巨大的代码味道.这些程序通常不能由用户运行而不会相互干扰(如果您为不同的程序重复使用临时表名称,并且不会重新创建它们,或者如果您使用相同的名称和两个不同的表格模式).它们可能很难排除故障 - 就像任何功能一样,必要时使用它们并且不存在更好的替代方案.临时使用真实表也可能有问题.

在SQL Server中完全相互传递数据的存储过程(超过参数)可能会有问题.现在有表值参数,现在可以使用内联表值函数或(并且通常优先于)多语句表值函数来完成以前用proc进行的许多事情.

在SQL Server中,避免在大型行集上大量使用标量函数和多语句表值函数 - 它们表现不佳,因此在C#中看起来很明显的模块化技术并不适用于此.

我建议你看看Ken Henderson的Guru的SQL Server存储过程指南 - 发表于2002年,它仍然有很多关于数据库应用程序设计的有用信息.