我什么时候应该使用存储过程?

时间:2009-07-23 13:34:21

标签: sql database stored-procedures

我应该何时使用存储过程而不是直接在我的应用程序中编写逻辑?我想获得存储过程的好处,但我也希望我的应用程序逻辑不会分散在数据库和应用程序上。

参考这个,你能想到任何经验法则吗?

20 个答案:

答案 0 :(得分:37)

哇...我要直接对抗当前的游泳并说“几乎总是”。有一个清单的理由 - 其中一些/我很确定其他人会争辩。但我开发了使用和不使用存储过程作为数据访问层的应用程序,而且我的经验是,编写良好的存储过程使编写应用程序变得更加容易。然后是有良好记录的性能和安全性优势。

答案 1 :(得分:19)

这完全取决于您的环境。这个问题的答案实际上不是编码问题,甚至是分析问题,而是商业决策。

如果您的数据库仅支持一个应用程序,并且与其紧密集成,那么出于灵活性的原因,最好将逻辑放在应用程序中。在这些情况下,将数据库简单地作为使用通用功能的普通数据存储库处理会使您失去灵活性并获得灵活性 - 包括供应商,实现,部署以及其他许多因素 - 以及'数据库用于数据'群众所做的许多纯粹论证都是示范性的真。

另一方面,如果您正在处理公司数据库,通常可以通过多个访问路径来识别它,那么最好尽可能地降低安全性。至少应启用所有适当的约束,并且如果可能,仅应通过视图和过程访问数据。在这些情况下,应该忽略呜呜的程序员......

  1. 使用公司数据库,资产很有价值,无效数据或操作可能会对业务造成威胁。您主要关注的是保护业务,而不是为您的程序员提供方便的访问。
  2. 根据定义,此类数据库可由多个应用程序访问。您需要使用存储过程提供的抽象,以便在升级应用程序A并且您没有资源升级应用程序B时可以更改数据库。
  3. 类似地,在SP中而不是在应用程序代码中封装业务逻辑允许比在应用程序代码中嵌入此类逻辑更容易和可靠地在整个业务中实现对这种逻辑的更改。例如,如果计算必须在一个SP中更改而不是多个应用程序,那么如果税收计算更改,则工作更少,更稳健。这里的经验法则是业务规则应该在最接近数据的位置实现 - 因此,如果您有专家应用程序,那么该应用程序的逻辑可以在该应用程序中实现,但逻辑更广泛适用应该在SP中实施业务。
  4. 关于使用或不使用SP的宗教战争的编码人员通常只在一个环境或另一个环境中工作,因此他们将他们有限的经验推断到铸铁位置 - 这在上下文中确实是完全可辩护和正确的他们来自但却错过了大局。与往常一样,您应该让您决定业务/客户/用户的需求,而不是您喜欢哪种编码方法。

答案 2 :(得分:10)

我在评论中说过这句话,但我会在这里再说一遍。

安全,安保,安全

当您的应用程序中嵌入了sql代码时,您必须将基础表公开给直接访问。这个可能一开始听起来不错。直到你遇到一些sql注入,它会扰乱数据库中的所有varchar字段。

有些人可能会说他们通过使用魔术引号或其他一些正确转义嵌入式sql的方法解决了这个问题。但是,问题是dev无法正确转义的一个查询。或者,忘记不允许上传代码的开发人员。或者,已破解的Web服务器允许攻击者上传代码。或者,......你明白了。很难涵盖你的所有基础。

我的观点是,所有现代数据库都内置了安全性。您可以简单地拒绝直接表访问(选择,插入,更新和删除)并强制所有内容通过您的s'procs。通过这样做,通用攻击将不再起作用。相反,攻击者必须花时间学习系统的私密细节。这增加了他们花费的时间和停止驱动和蠕虫攻击的“成本”。

我知道我们无法保护自己免受一切攻击,但是如果你花时间来构建你的应用程序,以便破解它的成本远远超过好处那么你就会严重降低数据丢失的可能性。这意味着要利用您可以使用的所有安全工具。

最后,关于不使用s'procs的想法,因为您可能必须移植到不同的rdbms:首先,大多数应用程序不会更改数据库服务器。其次,如果它是真正的可能性,你必须使用ANSI sql进行编码;你可以在你的过程中做什么。第三,无论如何,你都必须重新评估所有的sql代码,当代码在一个地方时,它会变得更加容易。第四,所有现代数据库现在都支持s'procs。第五,当使用s'proc时,您可以自定义调整它运行的数据库的sql,以利用该特定数据库的sql扩展。

答案 3 :(得分:5)

对我来说,复杂的数据库查询往往最终成为存储过程。另一个需要考虑的考虑因素是您的数据库可能与应用程序完全分离且不同。假设您运行Oracle数据库,并且您实际上正在为组织中的其他应用程序开发人员构建API以进行调用。你可以隐藏它们中复杂的东西,并在其位置提供存储过程。

一个非常简单的例子:

registerUser(username, password)

最终可能会运行一些不同的查询(检查它是否存在,在首选项表中创建条目等),您可能希望将它们封装起来。

当然,不同的人会有不同的观点(DBA与程序员)。

答案 4 :(得分:4)

基本上,当您必须执行涉及不需要离开数据库的数据的操作时。例如,您希望使用另一个表中的数据更新一个表,如果您可以一次性完成所有操作,那么将数据输出然后重新输入是没有意义的。

使用存储过程可以接受的另一种情况是,当您100%确定永远不会将应用程序部署到其他数据库供应商时。如果您是Oracle商店并且有许多应用程序在同一个数据库中进行通信,则可以使用存储过程来确保它们以一致的方式与数据库进行通信。

答案 5 :(得分:4)

我在3种场景中的1种中使用了存储过程:

<强>速度 当速度至关重要时,存储过程提供了一种很好的方法

<强>复杂性 当我更新几个表并且代码逻辑可能会改变时,我可以更新存储的proc并避免重新编译。存储过程是一种出色的黑盒方法,可以一次更新大量数据。

<强>交易 当我正在进行插入,删除或更新跨越多个表时。我将整个事情包装在交易中。如果出现错误,则很容易回滚事务并抛出错误以避免数据损坏。

底部2在代码中非常可行。但是,当复杂和事务级操作很重要时,存储过程提供了一种黑盒工作方法。否则,坚持使用代码级数据库操作。

安全性曾经是其中一个原因。但是,对于LINQ和其他ORM,代码级DAL操作比过去更加安全。存储过程是安全的,但LINQ等ORM也是如此。

答案 6 :(得分:4)

我倾向于避免存储过程。调试工具往往更原始。错误报告可能更难(与服务器的日志文件相比),至少对我来说,它似乎只是添加了另一种语言而没有真正的收益。

在某些情况下,它可能很有用,特别是在服务器上处理大量数据时,当然还有在代码中无法处理的数据库触发器。

除此之外,我倾向于在代码中做所有事情,并将数据库视为一个大的数据转储,而不是我运行代码的东西。

考虑Who Needs Stored Procedures, Anyways?

  

对于现代数据库和现实世界   使用场景,我相信一个存储   程序架构很严重   缺点和实用性   效益。 存储过程应该是   考虑数据库汇编语言:   仅用于最佳性能   危急情况。

Why I do not use Stored Procedures

  

你能做的绝对最糟糕的事情,   它在恐怖中非常普遍   微软的发展世界,就是为了   split related functionality between sproc's and middle tier code。   Grrrrrrrr。你只需要编写代码   脆弱,你增加了   理解的智力开销   一个系统。

答案 7 :(得分:2)

我倾向于总是使用存储过程。就个人而言,我发现它使一切都更容易维护。然后是安全性和性能方面的考虑。

请确保编写干净,布局合理且记录良好的存储过程。

答案 8 :(得分:2)

当所有代码都在存储过程中时,在需要时重构数据库要容易得多。对逻辑的更改也更容易推动。性能调优也要容易得多,并且大多数数据库应用程序迟早需要进行性能调整。

答案 9 :(得分:2)

我们使用存储过程来满足所有报告需求。他们通常可以更快地检索数据,并且报告可以直接吐出,而不必进行任何类型的计算或类似。

我们还将使用存储过程来处理我们需要执行的复杂或复杂查询,如果它们在我们的代码库中,则难以阅读。

答案 10 :(得分:2)

作为封装问题和DRY哲学,它也非常有用。例如,我使用存储函数在表中进行计算,我需要在代码中进行多次查询。这样我就可以使用更好的性能以及确保计算始终以相同的方式完成。

我不会将它用于更高的功能或逻辑应该在架构的业务逻辑层中,而是专注于模型层,其中功能明确侧重于数据库设计和可能的更改数据库设计的灵活性不会将API分解为其他层。

答案 11 :(得分:1)

除了速度和安全考虑之外,我倾向于尽可能多地使用存储过程以便于维护和更改。如果您将逻辑放在应用程序中,并稍后发现sql逻辑有错误或需要以某种方式工作,则必须在许多情况下重新编译和重新部署整个应用程序(特别是如果它是客户端应用程序,如WPF ,Win-Forms等)。如果你将逻辑保留在存储过程中,你所要做的就是更新过程,你永远不必触摸应用程序。

答案 12 :(得分:1)

我认为您应该避免使用存储过程。

我们为什么要避免呢?

  • 为避免应用程序和数据库之间的紧密耦合。如果我们使用存储过程,则将来将无法轻松更改基础数据库,因为我们必须:

    1. 将存储过程从一个数据库(例如DB2)迁移到另一个数据库(例如SQL Server),这可能很费时或...
    2. 将所有查询迁移到应用程序本身(或可能在共享库中)
  • 因为代码优先是一回事。有几个ORM可以使我们以任何数据库为目标,甚至可以管理表模式,而无需接触数据库。诸如Entity Framework或Dapper之类的ORM允许开发人员专注于构建功能,而不是编写存储过程并将其连接到应用程序中。

  • 开发人员要提高生产力还需要学习另一件事。相反,他们可以将查询编写为应用程序的一部分,从而使正在构建新功能和/或修复错误的开发人员更容易理解,维护和修改查询。

我知道一家严重依赖存储过程的公司。随着微服务数量的增加以及最初面向数据库的开发人员的离开,该公司留下了一个黑匣子,任何人都不得触摸,因为担心它会破坏一切。现在,他们希望转移到另一个数据库并转移到云中,这比需要做的要困难得多,而且无论如何它们都将存储过程逻辑转移到他们的应用程序中。

答案 13 :(得分:0)

我对此有过一些非常糟糕的经历。

我不反对代替存储过程,但是无偿使用存储过程可能非常昂贵。

首先,存储过程在数据库服务器上运行。这意味着如果您拥有一个包含50个Web服务器和一个数据库服务器的多服务器环境,而不是将工作负载分散到50个便宜的计算机上,那么您需要加载一个昂贵的计算机(因为数据库服务器通常构建为重量级服务器)。而且你冒着创造单点故障的风险。

其次,仅仅在存储过程中编写应用程序并不是一件容易的事情,尽管我遇到了一个超人类努力尝试的应用程序。因此,您最终需要维护成本高昂的东西:它以2种不同的编程语言实现,源代码通常也不在一个地方,因为存储过程最终存储在DBMS中,而不是存储在源存档中。假设某人管理/打扰过他们将他们从数据库服务器中拉出来并将其归档存档。

除了相当混乱的应用程序架构外,您还限制了可以维护它的合格黑猩猩的集合,因为需要多种技能。

另一方面,存储过程非常有用,IF:

  1. 您需要在多个系统中保持某种数据完整性。也就是说,存储的逻辑不属于任何单个应用程序,但您需要来自所有参与应用程序的一致行为。在外键和触发器形式的现代应用程序中,一定数量的这种情况几乎是不可避免的,但偶尔也可能需要进行主要的编辑和验证。

  2. 您需要的性能只能通过在数据库服务器本身上运行逻辑而不是作为客户端来实现。但是,正如我所说,当你这样做时,你正在吃掉DBMS服务器的总系统资源。因此,您应该确保如果有很多可以被卸载到客户端的违规操作,您可以将它们分离出来并为DBMS服务器留下最关键的内容。

答案 14 :(得分:0)

存储过程是一种收集操作的方法,应该在数据库端一起完成,同时仍然将它们保留在数据库端

这包括:

  • 从一个rowsource填充多个表
  • 根据不同的业务规则检查多个表
  • 执行使用基于集合的方法无法有效执行的操作

存储过程的主要问题是难以维护。

因此,您应该使存储过程与所有其他代码一样易于维护

我的博客中有一篇文章:

答案 15 :(得分:0)

您可能受益的特定情况涉及“(n + 1)”可伸缩性问题。任何类型的多维/分层情况都可能涉及这种情况。

另一种情况将涉及在处理表时执行某些协议的用例(提示:可能涉及事务的已定义步骤),这可以从引用的位置受益:在服务器中,查询可能会受益。 OTOH,您可以直接向服务器提供一批语句。特别是当您在XA环境中并且必须访问联合数据库时。

答案 16 :(得分:0)

如果你正在谈论业务逻辑而不仅仅是“我是否应该使用一般的sprocs”我会说当你执行基于大型集合的操作或任何其他时间执行逻辑时需要将业务逻辑放在sprocs中需要很大从应用程序调用数据库的次数。

答案 17 :(得分:0)

这也取决于您的受众。跨DBMS的安装和可移植性是否对您很重要?

如果您的程序应该易于安装并且易于在不同的数据库系统上运行,那么您应该远离存储过程,并在代码中注意不可移植的SQL。

答案 18 :(得分:0)

我同意他们应该经常使用。

我认为用例非常引人注目,非常有用的是,如果您要接收大量原始信息,这些信息应该分成几个表,其中一些数据可能已经存在且需要的记录通过外键id连接,那么你可以只是如果它没有检查和插入,或者如果它没有那么返回键,这使得从长远来看,一切都更加统一,简洁和可维护。

我建议反对使用它们的唯一情况是,如果您在查询之间进行大量逻辑或数字处理,最好在应用服务器中完成,或者如果您在公司工作在代码中保留所有逻辑对于可维护性/理解正在发生的事情非常重要。如果你有一个git存储库,里面装满了任何人都需要的东西,并且很容易理解,那就非常有价值。

答案 19 :(得分:0)

程序的使用在 2021 年仍然有意义吗?

也许在低级别和罕见的情况下,或者如果我们为具有毫无根据的限制的遗留公司编写代码,应该选择存储过程。

  • 如果整个逻辑都在数据库中,我是否需要 dba 来更改它?
    • 没有。在现代平台中,DBA 无法更改业务逻辑。
  • 在没有开发或暂存阶段的情况下对存储过程进行热修改,这是一个疯狂的想法。
  • 与使用初级开发人员能够维护的任何现代语言的 OOP 对象相比,维护具有数十行、游标和其他低级数据库功能的过程有多容易?
    • 这不需要更多评论。
  • 出于安全原因对我的开发团队隐藏表格对我来说听起来很疯狂,在这个敏捷性和良好的文档就是一切的时代。
    • 拥有现代数据库的现代开发团队,无需担心安全性。此外,他们需要访问沙盒版本的数据库以减少其交付时间。
  • 随着现代 ORM、ESB、ETL 和 CPU 能力的不断增加,存储过程不再是一种选择。我是否应该在这些工具上投入时间和金钱,最终创建一个大型存储过程?
    • 当然不是。