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

rye*_*guy 46 sql database stored-procedures

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

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

cod*_*key 38

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

  • *良好*记录的性能和安全性好处.只是想重述一下.我们不会将TSQL放在应用程序中,永远.SQL进入存储过程,从代码调用该过程.没有任何代码可以像选择语句那样触及.运行SP与否是预编译和解释代码之间的区别 - 您更喜欢哪一个?你的问题的答案是"总是". (8认同)
  • "记录良好"的性能项目实际上不是问题,具体取决于您使用的数据库引擎.但是,出于安全考虑,您应该始终使用存储过程.使用procs时,您可以拒绝直接访问表,从而完全保护自己免受大多数形式的破坏性SQL注入.否则你依赖代码来阻止它; 并非所有程序员都是平等的. (6认同)
  • @Chris Lively:参数化查询对于sql注入最安全.见http://palisade.plynt.com/issues/2006Jun/injection-stored-procedures/ (2认同)
  • @KB:首先,sql注入只是针对数据库的一个攻击媒介。其次,参数化查询不会使您免于上载带有嵌入式代码的恶意文档的攻击。如果开发人员忘记这样做,也不会挽救您。但是,简单地不允许一开始就直接访问表将阻止所有这些。 (2认同)
  • 我不能说我曾经不同意接受的答案,就像我不同意这个答案一样。当方案不断变化时,教条式的“一切都是SP”会引起很大的混乱。您不必阻止更改代码。您仍然必须从代码执行SQL。而且您使代码无法选择所需的数据。我找不到SP的所有价值。 (2认同)

Cru*_*han 21

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

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

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

  1. 使用公司数据库,资产是有价值的,无效数据或操作可能会对业务造成威胁.您主要关注的是保护业务,而不是为您的程序员提供便利.
  2. 根据定义,此类数据库可由多个应用程序访问.您需要使用存储过程提供的抽象,以便在升级应用程序A并且您没有资源升级应用程序B时可以更改数据库.
  3. 类似地,在SP中而不是在应用程序代码中封装业务逻辑允许比在应用程序代码中嵌入这样的逻辑更容易和可靠地在整个业务中实现对这种逻辑的改变.例如,如果计算必须在一个SP中更改而不是多个应用程序,那么如果税收计算更改,则工作量更少,更稳健.这里的经验法则是业务规则应该在最接近数据的位置实现 - 因此,如果您有专家应用程序,那么该应用程序的逻辑可以在该应用程序中实现,但逻辑更广泛适用应该在SP中实施业务.

关于使用或不使用SP的宗教战争的编码人员通常只在一个环境或另一个环境中工作,因此他们将他们有限的经验推断为铸铁位置 - 这在他们的背景下确实是完全可辩护和正确的.来但是错过了大局.与往常一样,您应该让您决定业务/客户/用户的需求,而不是您喜欢哪种编码方法.


Not*_*tMe 10

我在评论中这样说,但我会在这里再说一遍.

安全,安保,安全.

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

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

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

我知道我们无法保证自己不会遇到任何问题,但是如果你花时间来构建你的应用程序以便破解它的成本远远超过它的好处那么你就会严重降低数据丢失的可能性.这意味着要利用您可用的所有安全工具.

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


JRi*_*dsz 8

在 202X 中,程序的使用仍然有意义吗?

也许在低水平、罕见的情况下,或者如果我们为具有毫无根据的限制的遗留公司编写代码,则存储过程可能是强制性的。

首先我们对需求进行分类:

  • CRUD:创建、删除、更新、按自然 ID 搜索、列出所有
  • 查询:按isbn搜索书籍,按发行日期搜索书籍
  • 操作:以几行或几值作为返回进行计算。样本(银行业务、每月可数结算或每年)

还有一个术语:

  • 直接实现:我的意思是开发没有orm的sql命令。例如

  • ORM:一种将编程代码与数据库结构保持一致的方法。

    • jooq、hibernate、spring jpa 与 java
    • Node.js 的 knex
    • 用于 C# 的实体框架或 NHibernate(java hibernate 的副本)

以下是一些确定何时可以选择手术的提示

如果需求是严格的 CRUD

  • 应该使用 ORM
  • GraphQL有这个功能
  • 直接实施

如果需求是查询一个实体或资源

  • 应该使用 ORM
  • GraphQL有这个功能

如果需求类似于 CRUD 但需要条件(在插入/更新之前选择)

  • 如果负载和压力测试具有可接受的响应时间(小于 2 秒),则应使用 ORM

如果需求是一个操作,并且由于复杂性、行数、大量/大量而花费超过 2 秒

  • 该任务应该是异步的。我的意思是网页/系统或移动设备不应该等到后端完成繁重的任务(超过3秒)。
  • 在这种情况下,我建议使用一些 etl/esb 工具或使用 orm 来使用线程(并行处理)、版本控制、单元测试等高级功能,并对步骤/逻辑有一个可视化和记录的理解,而不是一个巨大的和具有数百行的 martian 存储程序
  • 使用 esb/etl 意味着牺牲 cpu 来获得上述优点
  • etls 和 esb 的真实 croos 平台是:(Pentaho)[https://pentaho-public.atlassian.net/wiki/spaces/EAI/pages/371557352/03.+Hello+World+Example] 和 (Mule Esb)[ https://developer.mulesoft.com/tutorials-and-howtos/getting-started/hello-mule/]
  • 检查本文的第一段以了解为什么复杂的操作应该是异步的: https: //devcenter.heroku.com/articles/request-timeout

如果业务需要繁重的操作在2秒之内完成:

  • 我们处于低水平场景
  • 只有在这种情况下,存储过程才是一个选项
  • 在这种情况下,现代团队使用低级语言(c++)或技术来解决此类需求。

以下是大多数情况下应避免存储过程的一些原因

整个逻辑都在数据库中

  • 需要 dba 在生产环境中创建过程
  • 在现代平台中,要求 DBA 更改业务逻辑是不可行的。

SQL 版本控制很痛苦

  • 在没有开发或暂存阶段的情况下热修改存储过程,是一个疯狂的想法。

  • 维护一个包含数十行、游标和其他低级数据库功能(如数据库链接、smtp 等)的过程有多容易?

    • 这是非常复杂的。
    • 使用 ORM 或任何现代语言加上文档(源代码级别和图表),即使是初级开发人员也能够维护代码

为了安全起见,对我的开发团队隐藏表格

  • 这对我来说听起来非常疯狂,在一个需要团队内部速度、知识共享(文档)的时代。
  • 现代开发团队拥有现代数据库,不应该担心安全性。此外,他们需要访问沙盒版本的数据库以减少交付时间。


cle*_*tus 7

我倾向于避免使用存储过程。调试工具往往更原始。错误报告可能会更困难(与服务器的日志文件相比),至少对我而言,似乎只是增加了另一种语言而没有任何实际收获。

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

除此之外,我倾向于做所有代码工作,并将数据库视为大量数据转储,而不是在上面运行代码。

无论如何,考虑谁需要存储过程?

对于现代数据库和现实世界中的使用场景,我认为存储过程体系结构有严重的缺点,几乎没有实际的好处。应将存储过程视为数据库汇编语言:仅在性能最关键的情况下使用。

以及为什么我不使用存储过程

您可以做的绝对最糟糕的事情是在sproc的中间层代码之间拆分相关的功能,这在Microsoft开发界非常普遍 。rr 您只需使代码易碎,就会增加理解系统的知识开销。

  • “数据库汇编语言”?这是荒谬的。这是_same_language_-transact-sql。我不主张在中间层和数据层之间拆分业务逻辑,但您的中间层应仅使用SP来处理数据。这是一种性能,除非您使用一些不预先编译存储过程的糟糕的rdbms。我想听听一个“严重的缺点”。 (6认同)
  • 不好的例子并不能消除正确使用方法的优点。 (3认同)
  • 就像曾经提高汇编语言的性能很重要一样,现在对于大多数用途而言,它已经无关紧要了。非托管代码(例如C / C ++)的性能优势一度成为重要因素。现在(大部分)不是。当然,还有其他原因可以使用上述方法。今天,SP的任何假定的性能提升同样(大部分)都无关紧要(在极端情况下除外)。可维护性,易于开发(例如,单元测试)等等**都更为重要**。 (3认同)
  • 不能同意更多..“没有真正的收获”吗?避免往返不是收获?(并且在大多数情况下,适当的SP可以节省多次往返)。整理并通过提高可维护性,获得数据库访问代码不是一件难事吗? (2认同)

Otá*_*cio 5

基本上,当您必须执行涉及不需要离开数据库的数据的操作时。例如,您想用另一个表中的数据更新一个表,那么如果您可以一次将所有数据都发送到数据库中,那么先将数据取出然后又重新存储就没有多大意义。

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


Dav*_*gan 5

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

一个非常简单的例子:

registerUser(username, password)
Run Code Online (Sandbox Code Playgroud)

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

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