我在全球三大IT咨询公司之一的一个项目中工作,一名DBA告诉我,公司的最佳实践的状态存储过程不是“最佳实践”。这完全违反了我所学到的所有知识。 ,可以保护您免受SQL注入攻击,并提高速度(尽管DBA表示,从SQL Server 2008开始,如果常规SQL查询运行了足够的时间,那么它们也会被编译)。使用敏捷软件开发方法开发复杂的应用程序。有谁能想到为什么不想使用存储过程的充分理由?我的猜测是,DBA不想维护那些存储的proc,但是似乎有太多的负面因素无法证明这种设计决定是正确的。

评论

它增加了什么代码重用?如果您的客户端使用其他数据库该怎么办。必须丢弃所有这些SP并从头开始。不要保护您免受sql注入。在大多数情况下,速度是最小的。

请记住,大多数大型I.T.咨询公司的动机是最大化可计费时间,同时保持自己的资产。在这些公司中有影响力的老手也往往是参与者和官僚,而不是技术人员。我会从咨询公司中拿出一些钱来做这样的事情-我已经不止一次地通过完善其“最佳”实践来使咨询公司摆脱困境。

@Rig代码重用与对任何语言的功能一样,通过将代码包装在可重用的容器中来添加。当然,只要不执行已构建的字符串,存储过程实际上就可以保护您免受SQL注入。要说速度是最小的,似乎根本没有学过。大多数情况不会在性能收益上归为同一类,但表现出很大的差异。

@GaretClaborn但是,重新构建应用程序层的可能性要比多年的历史数据库数据高得多。无论如何,在任何非平凡的应用程序上。如果这样做,您将花费数月时间移植存储过程丰富的代码。除了在极端情况下之外,向项目中再添加一个依赖项几乎没有什么好处。这些确实存在,但是在大多数情况下,这仅增加了项目敏捷性和代码重用的另一个障碍。

从我们几乎专门使用sps的背景来看,我可以告诉您远离它们并使用诸如Entity Framework这样的ORM的好处。业务逻辑被封装在过程中的次数太多了。虽然可以使用某些工作和/或第三方工具对proc进行版本控制。在TFS或GIT之类的框架中,这样做并不容易。发出的数据库代码与RDBMS提供程序无关。这样一来,您以后就可以关闭RDBMS提供程序,而不必担心。

#1 楼

根据我从事大型项目的经验,您必须非常清楚业务逻辑的用途。如果您允许单个开发人员将业务逻辑放在他们认为合适的业务对象层或存储过程中的环境,那么大型应用程序将变得非常难以理解和维护。

存储过程很棒用于加快某些数据库操作。我的体系结构决定是将所有逻辑保留在应用程序的业务层中,并以有针对性的方式采用存储过程来提高性能,以进行基准测试表明必须这样做。

评论


我看不到那么简单。对我来说,这就是所有业务逻辑。具有或不具有存储过程的数据库都提供某些服务并提供某些保证。理想情况下,错误的应用程序代码不可能使数据库处于不一致状态。如果需要存储过程来保持这种一致性,则可以使用它们。

–kevin cline
2011年4月7日在2:38



@kevin cline:定义“不一致状态”。我同意参考完整性之类的数据库功能很有价值,并且可以极大地减少应用程序错误导致严重损害的可能性。但是,一般而言,“一致数据”的定义取决于正确执行业务规则。

– Eric J.
2011年4月7日在3:46



将我的百万加到Mayo的百万。分布式业务逻辑使您摆脱了良好实践的道路,直奔疯狂

–尼科
2011年4月7日在9:23

使用存储过程时,+ 1业务逻辑渗入DAL是一个非常重要的问题。

–系统停机
2011年4月7日15:59

@ChristopherMahan,我永远都不想使用您设计的数据库。从数据库角度来看,这是最糟糕的做法。数据库通常直接受到数据库的影响。认为某人将使用业务层来更新一百万条记录或随着时间推移发生的其他事情是短视的。导入通常不会经过业务层(是的,我想在业务层一次处理2100万条记录的导入记录)。当您在数据库级别没有约束时,欺诈会容易得多。错误数据几乎可以肯定100%。

–HLGEM
2012年1月6日在21:05

#2 楼

一些观察结果

存储过程为您提供代码重用,
和封装(
软件开发的两大支柱),

只有在正确使用它们的情况下应该使用它们的上下文。关于功能(在结构化编程中)或方法(在面向对象编程中)的说法可以相同,但是,我们看到1K函数和巨型对象。正确使用这些工件才有这些好处。

安全性(您可以为单个存储的proc授予/撤消权限),

是。这是一个好点,也是我喜欢存储过程的主要原因之一。与仅使用视图和用户帐户通常可以实现的访问控制相比,它们提供了更好的粒度访问控制。

保护您免受SQL注入攻击,因为您可以使用参数化的SQL语句和输入清理来达到相同级别的保护。但是,除了“ SP的深度安全性”之外,我还将使用SP。在Server 2008中,即使运行常规SQL查询也可以进行编译(足够的时间)。确实会编译SQL语句(静态或参数化)。如果您希望/需要聚合和计算您无法使用简单的SQL语句完成但与SQL紧密集成且不保证与应用程序服务器往返的数据,SP可以提供帮助。到一个临时游标(或多个游标)中,从中运行另一个SQL本身。您可以在应用服务器中以编程方式进行操作,也可以通过在数据库中进行操作来保存多次往返。
但是,这不应该成为常态。如果您遇到许多情况,则表明数据库设计不良(或者您正在从跨部门的不太兼容的数据库架构中提取数据。)

我们正在使用
敏捷软件开发
方法论。

敏捷性与软件工程流程和需求管理有关,与技术无关。

谁能想到好的
他们不想使用存储的
进程的原因?使用GOTO”?在这个问题上,我与尼克劳斯·沃斯(Niklaus Wirth)的支持远胜于迪克斯特拉(Dijkstra)。我可以理解Dijkstra的情绪来自何处,但我认为这并非在所有情况下均适用100%。与存储过程和任何技术相同。
工具可以很好地用于预期目的,并且是完成特定任务的最佳工具。否则使用它并不表示该工具是错误的,而是表示焊工不知道他/她在做什么。
正确的问题是“应避免使用哪种类型的存储过程使用模式”。或者,“在什么条件下我(或不应)使用存储过程”。寻找不使用技术的原因只是将责任归咎于工具,而不是将工程责任直接归于其所属的领域-在工程师中。
换句话说,这是一种应对或声明。无知。

我的猜测是DBA不想
维护那些存储的proc,但是
似乎有太多的否定理由不能证明这种理由。一种设计决策。 />我的经验是,在罗马时,就像罗马人一样。
不要打架如果您公司的员工希望将存储过程贴上标签,这是一种不良做法,请允许他们。但是,请注意,这可能是其工程实践中的一个危险信号。
通常,在一些有大量不称职的程序员的组织中,通常将其标记为不良实践。通过将某些事物列入黑名单,组织试图限制由于自身能力不足而在内部造成的损害。我不拉你。说存储过程(或任何类型的技术)是不好的做法,这是一种概括。概括是无能的解决方案。工程师不能进行公然的概括。他们会根据具体情况进行个案分析,权衡分析并根据手头的事实执行工程决策和解决方案。
优秀的工程师可以做到不要以这种笼统的方式将事情标记为不良做法。他们着眼于问题,选择合适的工具,进行权衡。换句话说,它们可以进行工程设计。可以在其中放入一些数据按摩逻辑,或者将多个查询的结果聚合在一起。就是这样。超出此范围的任何内容都可以视为应该驻留在其他地方的业务逻辑。


不要将它们用作防御SQL注入的唯一机制。您可以将它们留在这里,以防万一有坏事发生,但是在它们前面应该有一系列防御性逻辑-客户端验证/清理,服务器端验证/清理,可能转换成对您有意义的类型域模型,最后传递给参数化的语句(可以是参数化的SQL语句或参数化的存储过程。)


不要使数据库成为唯一包含存储过程的地方。您应该像对待C#或Java源代码一样对待存储过程。也就是说,源代码控制商店过程的文本定义。人们对存储过程的抱怨不能由源控制-废话,他们只是不知道他们在说什么该死的地狱。


我对如何/在何处使用它们的看法


您的应用程序需要从多个查询或视图转置或聚合的数据。您可以将其从应用程序卸载到数据库中。在这里,您必须进行性能分析,因为a)数据库引擎在执行这些操作方面比应用服务器更高效,但是b)(有时)应用服务器在水平方向上更易于扩展。细粒度的访问控制。您不希望某些笨蛋在数据库中运行笛卡尔联接,但是您不能仅仅禁止人们像这样执行任何SQL语句。一种典型的解决方案是允许在开发和UAT环境中使用任意SQL语句,而在systest和生产环境中禁止使用它们。任何必须进入系统测试或生产的语句都会进入存储过程,由开发人员和dbas进行代码审查。经历不同的用户名/帐户和连接池(高度监视和劝阻使用)。在像Oracle这样的系统中,您可以访问LDAP或创建到外部数据库的符号链接(例如,通过vpn在业务合作伙伴的数据库上调用商店proc。)执行意大利面条式代码的简便方法,但这对所有编程范例都是正确的,并且有时您具有特定的业务/环境要求,这是唯一的解决方案。存储过程可帮助您轻松地在一个地方将这种麻烦封装在靠近数据的地方,而不必遍历应用服务器。

您是将它作为存储过程在数据库上运行还是在应用服务器上运行,这取决于您作为工程师必须进行的权衡分析。两种选择都必须进行分析,并通过某种类型的分析来证明其合理性。通过简单地指责另一种替代方法是“不好的做法”而走了一条路,这只是一个la脚的工程学解决方案。 (例如,没有用于新硬件或云实例的预算),但是在数据库后端具有足够的容量(这是很多人都愿意承认的典型),因此必须花钱将业务逻辑存储到proc中。不够漂亮,可能会导致贫乏的领域模型……但随后又要……进行权衡分析,这是大多数软件黑客所吸纳的东西。

这是否成为永久性解决方案,具体以限制在特定时刻观察到的问题。
希望有帮助。

评论


这是一个很好的答案。

– yfeldblum
2011年4月7日23:52

好的答案,但这是要讽刺吗? “概括是所有失败的源头。”

– Bedwyr
13年2月18日在3:28

是的,不。我的评论旨在用于OP在其原始问题中提到的特定句子(存储过程不是“最佳实践”。)对存储过程的最佳或不良实践进行粗略描述是一种概括。在设计或设计解决方案时,忽略它们可能是好是坏的环境可能(并且通常会导致)麻烦;)

–luis.espinal
13年2月19日在16:24



+1表示“通常将事情标记为不良做法,通常是在拥有大量无能的程序员的组织中进行的。” -在那里经历了整个过程,包括一名开发经理告诉我他认为我对一个棘手的问题有很好的解决方案,但是如果他被允许我实施,那么它将为开发人员打开闸门。木偶。

–朱莉娅·海沃德(Julia Hayward)
2014年9月4日15:20

@Shane你是对的。但是,我相信此答案试图传达的是某些工程师群体倾向于通过调用不良实践卡片来借以缺乏知识或分析的借口。不过,对于我们较缺乏经验的人,答案可能会有所改善。

–塞萨尔·埃尔南德斯(Cesar Hernandez)
'18 Sep 19'在19:32

#3 楼

其基本原理是,依赖于存储过程层会限制可移植性,并将您与某个数据库绑定。也有增加维护成本的原因。我还想对您提出的这一点发表评论:


(存储过程)保护您免受SQL注入攻击的侵害


可以保护您,您可以在纯文本sql查询中轻松做到这一点。

评论


而且,如果您存储的proc正在使用任何类型的动态sql和字符串参数,那么您就回到了起点。

– JeffO
2011年4月7日在17:52

不同之处在于可以基于每个过程为存储过程设置访问许可权,对于参数化SQL查询,您必须依靠程序员的理智而不是+“ blablabla”,因为您必须允许使用普通SQL,而这就是控制的终点。

–编码器
2012年4月20日在3:58

我从未理解过“将您与某个数据库联系起来”的说法。您多久采用一次程序并将其迁移到完全不同的数据库?

–梅森·惠勒
2012年6月14日在18:07

@MasonWheeler-每次+1。在任何足够大的项目中,您的应用程序最终都是根据给定数据库产品的缺点编写的。无论如何,转换为另一个数据库都成为一项主要工作,因为新数据库将具有不同的可能性!

–迈克尔·科恩(Michael Kohne)
2012年6月14日18:09

@HLGEM-但是在COTS世界中,一开始会期望有多个DB(实际上,您选择了兼容的DB)。不是移植,而是支持不同的后端,这与移植完全不同。

–迈克尔·科恩(Michael Kohne)
2013年6月5日18:34

#4 楼

我同意存储proc的某些原因不是最佳做法。


业务和应用程序逻辑应该在代码中,而不是数据库中。将逻辑放入数据库中令人担忧。
您无法像其他常规应用程序逻辑中那样,用其余的应用程序逻辑对存储的过程进行无缝测试。
我找不到存储的过程。因为在编写代码时有利于测试首次编程。
在IDE中调试程序时,存储的procs不像应用程序代码那么容易调试。
SP的版本控制/源代码控制与常规代码


评论


您可以像对存储过程进行测试优先编程一样容易。

–user1249
2011年4月7日在6:57

嗯,嗯... 1)使用db存储过程不一定意味着要在其中存储业务逻辑。 2)存储的proc是最容易进行单元测试的内容。 3)存储过程不一定遵循测试优先实践,这是正确的,但并非所有可计算的事物都可以测试优先。 4)调试应该不是问题,因为存储过程应该只包含易于验证的SQL语句和游标。同样,调试应该通过首先对代码中的SQL语句进行测试和调试来进行,然后再移至存储过程中……仅是IMO btw。

–luis.espinal
2011年4月7日在16:30

您显然不是数据库开发人员。源代码管理(IDE)-如果您使用的是TOAD或类似的IDE(版本控制),则非常容易调试SP。

– gbjbaanb
2011年7月21日在11:02

2)关于单元测试存储过程。关于其他单元测试框架的idk,但至少与MS Test(VisualStudio.TestTools.UnitTesting)结合使用,在存储的proc上运行任何Assert方法至少需要一个Db连接,根据定义,它比单元更像一个集成测试测试。并且存储的过程可以在全局数据库级别上引用关于数据库的状态。这些可能不是伪造的或具有接口。

– T. Webster
2012年1月7日7:50

+1此外,存储过程语言(pl / sql,t-sql,plpgsql等)非常笨拙且冗长。使用脚本语言建立数据库连接并处理数据库外部的业务逻辑对我来说要容易得多。

–user11946
2012年6月13日19:31

#5 楼


是的,存储过程为您提供代码重用和封装(软件开发的两大支柱),是的,但是要以能够满足其他敏捷设计目标为代价。一方面,它们更难以维护。如果我参与的项目有任何迹象,您最终可能会得到多个不兼容的SP,这些SP基本上完成了相同的工作,而没有任何好处。攻击,


否。他们不。正如我经常听到的那样,我什至无法开始猜测这个想法可能从何而来,这根本不是真的。它可以缓解某些类型的SQL注入攻击,但是如果您首先不使用参数化查询,那将无关紧要。我仍然可以'; DROP TABLE Accounts; -


并有助于提高速度(尽管DBA表示从SQL Server 2008开始,即使常规SQL查询运行了足够的时间,它们也会被编译)。


使用准备好的,参数化的语句(至少与我使用的几个DB一起使用)时,通常也会对它们进行编译。在您的应用程序开始执行查询时(或特别是当您多次执行相同的准备好的查询时),您认为SP所具有的任何性能优势都是完全没有意义的。

使用存储过程,恕我直言,是您必须进行一个复杂的,多阶段的查询,该查询从多个整理的数据源中提取。 SP不应包含低级决策逻辑,并且它们绝不应简单地封装否则为简单的查询。没有好处,只有很多缺点。

听您的DBA。他知道怎么回事。

评论


Red Gate有一个用于SQL Server的产品SQL Source Control,但是我同意,将逻辑推入存储的procs是确保您的重要逻辑不受任何版本控制的绝佳方法。

– Carson63000
2011年4月7日在11:59

@greyfade-“我还没有看到SP的源代码控制”-您在跟我开玩笑吗?商店proc只是您在数据库引擎中上载的血腥文本文件(它会对其进行处理,编译并安装以执行)。在我工作过的每个存储proc的地方,我们都将商店proc源代码存储在其中,例如CVS,clearcase或使用的任何SCM。说存储过程不能被源代码控制(因为它们在db中)就像说我的应用程序源代码(Java,C#或其他任何东西)不能被源代码控制,因为它是在生产中编译和部署的。

–luis.espinal
2011年4月7日在16:34



@ luis.espinal:我没有说他们不能处于源代码控制中。我只是说我不知道​​专门用于维护SP历史的工具,这意味着要在数据库中维护该历史。请不要只因为您读错了东西而对我rant之以鼻。

– Greyfade
2011年4月7日在16:39

所有opur存储的proc都在源代码管理之下,只是因为您过去曾看到过不良的表述并不意味着它们是使用存储proc所固有的。

–HLGEM
2011年4月7日17:00

@ luis.espinal,是否可以稍后从数据库中检索存储过程的源头,这很典型?如果是这样,您只需拥有一个可以定期将其拔出的工具,然后使用其他工具即可从头开始重新创建安装。偶尔执行一次以确保其准确性。

–user1249
2012年5月5日13:20

#6 楼

我工作的所有三家公司都将存储过程用于SQL Server的应用程序逻辑。相反,我还没有真正看到过事情。但是对我来说,它们真是一团糟。通常没有很好的错误处理工具或带有存储过程的代码重用工具。

假设您有一个存储过程返回了要使用的数据集,如何在其中使用它将来的存储过程? SQL Server上的机制不是很好。 EXEC INTO ...仅适用于一到两个嵌套级别(我现在忘记了)。或者,您必须预定义工作表并对其进行键控处理。或者,您需要预先创建一个临时表并让过程填充它。但是,如果两个人在两个他们从未计划同时使用的不同过程中将临时表称为同一件事,该怎么办?在任何普通的编程语言中,您都可以从函数返回数组或指向它们之间共享的对象/全局结构(函数语言除外,在函数语言中您将返回数据结构而不是仅更改全局结构... )

代码重用如何?如果您开始将通用表达式放入UDF(甚至更差的子查询)中,则会使代码停顿下来。您不能调用存储过程来为列执行计算(除非您使用游标,将列值一个接一个地传递,然后以某种方式更新表/数据集)。因此,基本上要获得最佳性能,您需要在整个维护工作的噩梦中到处剪切/粘贴通用表达式...使用编程语言,您可以创建一个函数来生成通用SQL,然后在构建时从任何地方调用它SQL字符串。然后,如果您需要调整公式,则可以在一个地方进行更改...

错误处理如何? SQL Server有许多错误会立即停止存储过程的执行,甚至会导致断开连接。自2005年以来,出现了try / catch,但是仍然存在许多无法捕获的错误。同样,错误处理代码上的代码重复也会发生同样的事情,您真的无法像大多数编程语言一样容易地传递异常或将异常冒泡到更高的层次.....

速度。数据集上的许多操作都不是面向SET的。如果您尝试进行面向行的操作,则要么使用游标,要么使用“游标”(当开发人员经常逐行查询每一行并将内容像游标一样存储到@变量中时)。 ..即使这通常比FORWARD_ONLY游标要慢)。在使用SQL Server 2000之前,我已经运行了1个小时,而我杀死了它。我在Perl中重写了该代码,并在20分钟内完成了代码。当比C慢20-80倍的脚本语言在性能上抽走SQL时,您肯定没有用SQL编写面向行的操作的业务。如果您使用CLR存储过程,请走开。但是出于安全考虑,许多DBA都不知道如何编写.NET程序或关闭CLR并坚持使用Transact SQL...。即使使用CLR,您仍然存在在多个过程之间高效地共享数据的问题。 。

通常,最难扩展的是数据库。如果您所有的业务逻辑都在数据库中,那么当数据库变得太慢时,您将遇到问题。如果您有业务层,则可以添加更多缓存和更多业务服务器以提高性能。传统上,另一台安装Windows / Linux并运行.NET / Java的服务器比购买另一台数据库服务器并为更多SQL Server授予许可要便宜得多。但是,SQL Server现在确实提供了更多的群集支持,最初它实际上没有任何支持。因此,如果您确实有很多钱,则可以添加群集,甚至可以做一些日志传送来制作多个只读副本。但是总的来说,这将比仅写缓存或其他内容花费更多。

还要看看Transact-SQL工具。字符串操作?我每天都会上Java String Class / Tokenizer / Scanner / Regex类。哈希表/链接列表/等等。我将使用Java Collection框架等。.NET也是相同的。C#和Java都比Transact SQL更进化。 。

在plus上,存储过程对于处理大型数据集并应用多个查询/条件缩小其范围,然后再将其返回到业务层更为有效。如果您必须向客户端应用程序发送一堆庞大的数据集并在客户端上分解数据,那将比仅在服务器上完成所有工作效率低得多。对安全性有好处。您可以削减对基础表的所有访问,仅允许通过存储过程进行访问。使用XML之类的现代技术,您可以具有执行批处理更新的存储过程。然后,通过存储过程控制所有访问,因此只要它们是安全/正确的,数据就可以具有更高的完整性。

由于我们已经在编程语言方面进行了参数化查询,因此SQL注入参数不再真正适用。甚至在参数化查询之前,实际上大多数时候也可以使用一个replace(“'”,“''”)来工作(尽管仍然有一些技巧可以使用字符串的结尾来获得所需的内容)。 br />
总体而言,我认为SQL和Transact SQL是用于查询/更新数据的出色语言。但是对于编码任何类型的逻辑,请执行字符串操作(或heck文件操作...。您会惊讶于xp_cmdshell可以执行的操作...。)请不要。我希望找到一个将来不主要使用存储过程的地方。从代码可维护性的角度来看,这是一场噩梦。如果您要切换平台,也会发生什么(尽管实际上,如果您购买了Oracle / DB2 / Sybase / Sql Server / etc。您也可以通过使用所有可以帮助您的专有扩展来获得所有功能。 ..)。

令人惊讶的是,业务逻辑常常是不同的。在理想情况下,您会将所有逻辑放入存储过程中并在应用程序之间共享。但是根据应用程序,逻辑常常会有所不同,并且存储过程最终会变得过于复杂,人们害怕更改并且不了解其所有含义。使用良好的面向对象语言,您可以编写一个数据访问层,该层具有一些标准接口/钩子,每个应用程序都可以根据自己的需要进行覆盖。

评论


但是,我不禁要对整个面向集合的问题与程序问题进行思考。我已经看到在所有情况下数据库游标都只是胡说八道。我亲自将基于显式游标的显式SQL(在特定情况下为Oracle PL / SQL)替换为面向集合的查询,并看到结果在一秒钟之内返回,而不是8分钟。我花了30分钟的时间来剖析并“获取”该1,000行光标代码。生成的SQL查询简洁,优雅,简单。人们过低且过快地低估了数据库服务器的功能。

– Craig
2014年3月21日在23:25

最大的错误:编写SQL应用程序与Java或.Net不同。您不会以与为SQL Server编写相同的方式为Oracle编写SQL。没有所谓的DB不可知应用程序。这是一个神话。如果编写与数据库无关的应用程序,很可能会破坏数据库的目的。

– Sabyasachi Mitra
20年6月19日在15:58

#7 楼

这是几年前我为五巨头之一工作时的官方电话。理由是,由于SP绑定到特定的实现(PL / SQL,T / SQL和...),因此它们不必要地限制了技术选择。

经历了从T迁移一个大型系统的过程。 / SQL到PL / SQL,我可以理解该参数。我认为这有点让人难过-究竟有多少地方一时兴起从一个数据库真正转移到另一个数据库?

评论


@DaveE:对于企业解决方案,您可能是对的。如果要创建打包的软件,则一旦在MSSQL上发布,您最大的希望就是希望它在Oracle上运行。

– Eric J.
2011年4月6日在22:09

@Eric:太正确了。我现在所处的位置,我们使用了大量的SP,并告诉人们“不”,如果他们不想要MSSQL。能够做到这一点真是太好了。

– DaveE
2011年4月6日在22:12

@DaveE:销售团队是否希望您说“是”?

– Eric J.
2011年4月7日在3:48

将一个系统从一个数据库迁移到另一个数据库并不是那么多,而是让一个系统能够使用客户已经拥有的任何数据库系统。大数据库很昂贵。

–user1249
2011年4月7日在7:03



@EricJ:是的,但是一旦他们看到了佣金的成本,请求就消失了。

– DaveE
2011年4月7日在16:32

#8 楼

如何在服务器上对存储过程进行版本控制?

如果从版本控制将存储过程重新部署到服务器,则会炸毁存储执行计划。

存储过程不应可以直接在服务器上进行修改,否则您怎么知道现在正在实际运行什么?如果不是,则部署工具需要访问权限以将存储过程写入数据库。您必须在每个构建上进行部署(执行计划可能需要有所不同)。虽然存储过程不可移植,但SQL通常都不是(曾经见过的oracle日期处理-uggghhh)。

因此,如果您希望具有可移植性,请构建一个内部数据访问API。您可以像调用函数一样调用此函数,并且可以在内部使用所需的语言内置参数化查询,并且可以对它进行版本控制。

评论


您如何在服务器上对存储过程进行版本控制? -您可以控制商店proc源代码的版本。当需要进行部署时,您(从给定的基准)获取存储过程,然后(或您的dba)部署到生产环境。重新部署(无论是在测试还是在生产中)肯定会炸毁存储的执行计划,但这将独立于您是否对SP进行源控制而进行。

–luis.espinal
2011年4月7日在16:38

@BarryBrown如果人们可以直接访问服务器并可以更改存储过程,则此方法将无效。我必须有一个监视SP的过程,或者在每次使用前都要检查一下...

–克里斯托弗·马汉(Christopher Mahan)
2012年5月7日21:40

如果您只是有人随意更改服务器上的存储过程而没有将更改提交给源代码控制,那么即使您不知道这样做,您也会遇到一个几乎肯定会影响命令式代码开发的过程问题。

– Craig
2014年3月13日在7:58

我过去做过的一件事是将数据库服务器的开发实例放在单个开发人员的工作站上,或者,如果不可能,那么至少要有数据库的“开发”和“生产”实例,所有DDL和DML脚本以及示例数据和加载脚本都位于源代码树中它们自己的目录下,并且通常使用MAKE文件从这些脚本中构建数据库。开发人员也可以使用nmake来构建单个存储的proc。如果他们不将其置于源代码控制之下,它将消失在他们身上,他们知道这一点。

– Craig
2014年3月21日23:10



……我并不是故意要在我先前的评论中用“……,即使您不知道……”这句话来轻蔑。我要传达的意思是,如果这种事情在存储过程中发生,那么它也可能在项目的其他部分中发生。我个人不喜欢集成开发环境中的集成源代码控制,部分原因是我认为这使人们在思考对团队和整个项目进行更改并将这些更改提交到源代码管理时真正意味着什么时变得很懒惰资料库。我认为这些事情不应该是“自动的”。

– Craig
2014年3月21日在23:16

#9 楼


这与我学到的一切都太相反了。


您可能需要更多。 [笑]严重的是,存储的过程已下降至少10年了。自从n层取代客户端服务器以来,几乎已经有了很多。下降只是通过采用Java,C#,Python等OO语言来加速的。进行讨论和辩论。这不是新事物,并且可能还会持续相当长的一段时间。 IMO,存储过程的反对者显然是赢家。


存储过程为您提供代码重用和封装(软件开发的两个支柱)

>非常正确。但是,体面的OO层也是如此。


安全性(您可以授予/撤消对单个存储过程的权限)


可以做到这一点,但由于严重的限制,很少有人这样做。数据库级别的安全性不够精细,无法做出上下文感知的决策。由于性能和管理方面的开销,也很难建立基于每个用户的连接-因此,您的应用程序代码中仍然需要一定级别的授权。您可以使用基于角色的登录名,但是您将需要为新角色创建它们,维护您以哪个角色运行,切换连接以执行“系统级”工作,例如登录等。最后,如果您的应用是是拥有的-您与数据库的连接也是如此。


保护您免受SQL注入攻击


除了进行参数化查询外,别无其他。您仍然需要执行此操作。


并有助于提高速度(尽管DBA表示从SQL Server 2008开始,即使常规SQL查询运行足够的时间,它们也会被编译) 。


我认为这始于MSSQL 7或2000。关于存储proc与内联SQL性能的争论,度量和错误信息很多-我全都放在YAGNI下。并且,如果您确实需要,请进行测试。


我们正在使用敏捷软件开发方法来开发复杂的应用程序。任何人都可以考虑为什么不想使用存储的proc的充分理由吗?


我想不出很多原因。 Java / C#/任何第3种GL语言在封装,重用和可混合性等方面都比T-SQL强大得多。考虑到ORM不错,其中的大多数都是免费的。

建议“根据需要分配,但不分配更多”-我认为这些天的举证责任在SP倡导者身上。使存储过程繁重的一个常见原因是T-SQL比OO更容易,并且商店比T.SQL具有更好的T-SQL开发人员。或者,DBA停在数据库层,而存储的proc是dev和DBA之间的接口。或者,您正在运送半定制产品,并且存储的过程可以由用户定制。缺乏这样的考虑,我认为这些天任何敏捷软件项目的默认设置都是ORM。

评论


如果您不必从数据库中转移出巨大的数据集来做简单的事情,就有很多方法可以提高性能。测量并根据需要进行优化。

–user1249
2012年5月5日13:23

恰恰。存储过程可以像手术刀一样使用。绝对保证数据库服务器内部的I / O比数据库服务器和中间层之间的I / O具有更多的带宽。而且,您不会在中间层中编写比在数据库服务器中编写的数据库引擎开发人员更快,更有效的数据联接代码。如果您要将1,000,000行数据传输到中间层以进行联接(我已经肯定地看到过),那您就应该被弄糊涂了。疯狂。

– Craig
2014年3月21日在23:28

不要低估您的数据库服务器。了解如何正确使用它。

– Craig
2014年3月21日在23:29

FWIW,您不需要存储的proc就可以在数据库端进行联接。而且,如果您将游标用于过程逻辑,则可能已经失去了性能之战。放弃存储过程肯定与放弃SQL或基于集合的解决方案不同。

– Mark Brackett
2014年3月21日在23:46

完全正确,我实际上是在支持SQL,而不是专门针对sproc。但是,将SQL嵌入命令式代码中也不一定是幸福的关键,对吧?这常常引起整个ORM争论,然后导致我指出ORM驱动的数据库访问与仅学习如何使用SQL之间的性能比较。我曾经见过并且听说过这样的系统,例如,Oracle顾问建议将所有负载都保留在数据库服务器之外,从而导致性能令人讨厌的重型(非常昂贵!)中间件。

– Craig
2014年3月22日,0:35

#10 楼

考虑到上述所有情况,我想再添加一个。
SP的选择也可能取决于人们的选择。 SP,我相信这样的SP维护和调试非常复杂。甚至在很多情况下,开发人员本人都面临着在后台进行代码调试(例如说语言部分)时比在SP中容易得多的问题。

SP仅应用于简单的操作。那是我的选择。

#11 楼

我想同时介绍存储过程的一些利弊。我们在LedgerSMB中广泛使用它们,我们的规则是,通过一些非常具体的扩展,“如果是查询,则将其存储为过程。”

我们这样做的原因是为了促进交叉语言查询重用。老实说,没有比这更好的方法了。

最后,问题总是在细节上。如果使用得当,存储过程会使事情变得容易得多,而使用不当则会使事情变得更加困难。使用过的存储过程很脆弱。单独使用它们可以为您在您没有意外的地方(除了调用语法已更改之外)添加代码错误的可能性。单独使用会有点问题。层之间的内聚性太大,这会引起问题。在这个领域过分自信是一件坏事,因此需要在该领域的安全方面有丰富的经验。
由于上面的原因1,更改存储过程的接口有些问题,但这可能会变成如果涉及大量客户端应用程序,这将是一个巨大的噩梦。

上面的内容很难否认。他们发生了。支持SP和反SP的每个人都可能有关于这些的恐怖故事。这些问题并非无法解决,但是如果您不关注它们,就无法解决(在LedgerSMB中,我们使用服务定位器在运行时动态构建SP调用,从而完全避免了上述问题。只能对其他数据库执行类似的操作。)

肯定。假设您可以解决上述问题,您将获得:


设置操作中增强清晰度的可能性。如果您的查询很大或非常灵活,则尤其如此。这也导致增强的可测试性。
如果我已经在该领域工作过服务定位器,那么我发现存储过程可以加快开发速度,因为它们使应用程序开发人员摆脱了数据库问题,反之亦然。这在做对时会遇到一些困难,但并不难。
查询重用。 >

非事务逻辑。您发送了一封电子邮件,说明订单已发货,但交易已回滚...或者现在您正在等待继续使电子邮件服务器联机....或者更糟糕的是,由于无法到达而回滚了交易电子邮件服务器。...
松散地串在一起的许多小查询,散布着过程逻辑....

评论


强烈同意,例如:将非事务性垃圾排除在存储过程之外。在该电子邮件示例中,无论如何,应将电子邮件消息放入队列并进行异步服务。谈论要让自己在负载下产生巨大的性能影响和时髦的行为,使数据库事务依赖于邮件服务器的响应吗? kes!

– Craig
2014年3月23日在2:25

#12 楼

您为谁工作?

答案可能取决于您雇用的人,咨询公司或公司本身。对于公司而言,最好的情况通常对咨询公司或其他软件供应商来说不是最好的。例如精明的公司希望拥有比竞争对手持久的优势。相比之下,软件供应商希望能够以最低的成本为特定行业的所有企业提供相同的解决方案。如果他们成功了,客户将没有任何净竞争优势。

在这种特殊情况下,应用程序来来往往,但企业数据库却永远存在。 RDBMS要做的主要事情之一是防止垃圾数据进入数据库。这可能涉及存储过程。如果逻辑是好的逻辑,并且极不可能每年更改,那么无论使用哪种应用程序编写数据库,为什么都不应将其保留在数据库中并保持内部一致性?几年后,有人会问他们要问数据库的问题,如果阻止了垃圾邮件进入数据库,这将是可以回答的。

因此,这可能与您的DBA有关在一家咨询公司工作。他们编写代码的可移植性越强,它们在客户端之间重用代码的可能性就越大。他们可以在应用程序中使用的逻辑越多,公司与供应商的联系就越多。如果他们在此过程中留下了大麻烦,他们将获得报酬来清理它,或者再也看不到混乱了。不管怎么说,对他们来说都是胜利。



对于(很多)篱笆两侧的更多讨论,请阅读编码恐怖的讨论。 FWIW我倾向于那些主张SP的人。

评论


该答案的重点是将是否使用存储过程的问题与您为谁工作以及他们的动机是什么相关联。下注。相反,答案应该集中在将存储过程的优缺点与是否使用存储过程联系起来。如果答案集中在SP阻止垃圾进入数据库的想法,那我就不会低估。为了公开的目的,我不同意,但我不会拒绝。

– yfeldblum
2011年4月7日,下午1:53

您还链接了2004年的一篇文章,恕我直言,此后情况发生了很大变化。 OR / M已经变得越来越普遍。 Ruby / Rails ActiveRecord,MS附带linq和EF,Django适用于python等。

–布鲁克
2011年4月7日在2:25

@Justice,他是对的,不过,storageprocs领域的最佳实践是否取决于公司的性质以及他们所扮演的角色。例如,存储的proc允许您对proc本身而不是直接在表上设置权限。如果您正在进行任何财务工作,并且必须考虑内部控制,则它们是保护您的数据免遭用户使用的唯一可行选择。但是,如果您要创建可能具有多个后端的COTS产品,则它们也是特定于数据库的。如果您是一家咨询公司,则可能需要考虑几种不同的方法,以适应具体情况。

–HLGEM
2011年4月7日在17:08

@HLGEM我不反对您提出的任何观点。但是我反对答案的论点,即DBA可能在应用程序中添加逻辑的主要原因是因为他是一名顾问,并且打算欺骗客户。它把一个人的道德立场与他是否使用存储过程的选择联系起来。我认为双方都有技术论点,双方的论点在应用程序,应用程序,技术到技术,公司到公司,行业到行业之间会有所不同。我将首先寻找功绩,然后再去破坏动机。

– yfeldblum
2011年4月7日23:30

他说他在一家咨询公司工作。与部署到客户站点的存储过程相比,对代码保持更多控制是一个非常合理的理由,这可能是他们的“最佳实践”。可能不是“吸引客户”,而是完全可以控制的问题。

–杰西
2012-2-23在8:32

#13 楼

切换数据库品牌和使用相同的存储过程非常困难。 />这无非是程序员与DBA的小便竞赛。

#14 楼

IMO这取决于。存储过程虽然占了上风,但不是最佳实践,也不是不惜一切代价避免的事情。精明的开发人员知道如何正确评估给定情况并确定存储过程是否是答案。就个人而言,我喜欢使用某种ORM(甚至是像原始Linq到Sql这样的基本ORM),而不是使用存储过程,除了可能用于预定义的报告或类似的报告外,但这确实是个案的基础。

评论


下注者应发表评论。

– SandRock
2012年5月4日19:29

#15 楼

使用不同的编程语言将业务逻辑划分到不同的层之间,始终是问题的根源。当您必须在不同的环境之间切换时,跟踪错误或实施更改会变得更加困难。 。这些不是很大的应用程序,但也不是简单的。例如20K-100K LOC。 (PL / SQL比T-SQL更适合于这种系统,因此,如果您只了解T-SQL,您可能现在就摇摇头……)

#16 楼

这是尚未提到的另一点:

代码生成工具和逆向工程工具不能真正很好地应对存储过程。该工具通常无法分辨proc的作用。 proc是否返回结果集?几个结果集?是否从几个表和临时表中获取结果集? proc是封装的update语句,不返回任何内容吗?它会返回结果集,返回值和一些“控制台输出”吗?

因此,如果要使用工具自动创建数据传输对象DTO和DAO层(例如liferay的“服务提供商”),那么您就不容易这样做。

此外,当数据源是SP时,像Hibernate这样的ORM不能真正正常工作。数据访问最多是只读的。

评论


有趣的是,当存储过程本身没有任何麻烦时,代码生成工具显然很难弄清楚存储过程是否返回结果集。

– Craig
2014年3月23日在2:29

#17 楼

单独编程,我无法抗拒编写存储过程。

我主要使用MySQL。我以前没有像PostGreSQL那样使用过面向对象的数据库,但是我在MySQL中对SP所做的事情就是抽象了表结构。 SP允许我设计这些原始动作,即使其下的数据库确实发生了变化,其输入和输出也不会改变。登录时,始终只需传递logInusername。返回的结果是整数password

userId是存储过程时,现在我可以添加与初始登录同时发生的其他登录工作。与在编写逻辑服务器端时要做的(调用环境FETCH)->(获取结果)->(调用环境FETCH)系列相比,在存储过程中具有嵌入式逻辑的一系列SQL语句更容易编写。 >

#18 楼

我还要指出,存储过程确实在服务器上使用cpu时间。不是很多,但是有些。在工作过程中完成的某些工作可以在应用程序中完成。扩展应用层比扩展数据层更容易。

评论


扩展数据库难吗?

– JeffO
2011年4月7日在17:47

至少要贵很多(除非您在MySQL上如此),而且在许多地方,我一直在努力获得另一个SQL Server Enterprise Edition许可证,就像在咬牙。

–ben f。
2011年4月7日在18:16

扩展数据库并不比扩展应用程序层的故事难。

–布赖恩·奥格登(Brian Ogden)
17 Mar 23 '17 at 4:55

#19 楼

我同意Mark的观点,即社区确实已经离开存储过程已有相当一段时间了。尽管原始发布者提出的许多观点一次都有效,但我们已经使用了相当长的时间,而且正如另一位发布者所说,环境已经改变了。例如,我记得一个关于“在一天之内”使用SP的论点是获得的性能提升,因为它们的执行计划是“预编译”的,而每次执行时都必须“重新编译”来自我们代码的动态SQL。不再是这种情况了,因为主要数据库已经更改,改进,改编等。

这就是说,我们在我当前的项目中正在使用SP。原因仅仅是因为我们在仍支持旧版应用程序的现有数据库之上构建新应用程序。因此,在我们关闭旧版应用程序之前,很难进行架构更改。我们做出了一个明智的决定,即根据应用程序所需的行为和规则来设计新应用程序,并使用SP临时连接数据库,并允许SP适应现有的SQL。 。这可以说是以前的观点,即SP使得在数据库级别进行更改变得更容易,而无需更改应用程序代码。使用SP作为Adapter模式的实现对我当然是有意义的(尤其是考虑到当前的项目),并且可能是我今天真正看到它们可以使用的唯一论点。我们打算在更新架构时删除SP。但是,与公司发展中的所有其他事情一样,我们将看看这种情况是否会发生! [咧嘴]

#20 楼

我只是想简要概述如何建议使用存储过程。我认为这根本不是一个坏习惯,就像其他人所说的那样,应该在适当的情况下使用它们。分离应用程序的业务逻辑,并导致数据库变得更加混乱和严格。换句话说,如果存在用于数据库操作的逻辑,该逻辑与任何应用程序的数据一致,则可以使用存储过程来保持数据的一致存储(有意义)。我认为,很好的例子是:一致的日志记录,一致的维护,使用敏感信息等。我认为数据库应该存储在包含业务逻辑的另一层中。简而言之,为实现一致性而进行的特定于数据库的数据操作可以使用存储过程,其中一致性超出了数据库完整性模式模型的范围。

#21 楼

除了不必要地分发业务逻辑,并将您与特定的数据库供应商联系在一起之外,我还坚信按照预期的目的使用技术。数据库就是关系数据存储。用它来存储数据,别无其他。

明智地选择工具,从长远来看,将为自己省去很多麻烦。

评论


如果您要减票,请这样做,但至少要说明原因。

–尼科
2011年4月8日在6:37

可能是因为您错了。 SP并不意味着您在其中编写代码,而只是编写数据访问查询(我认为有99%的情况)。此外,仅将触发器和约束放在数据模型上就被视为“代码”,即操作逻辑,而不是数据。因此,我的观点是你错了。

– gbjbaanb
2012年4月20日在11:47

除了数据库中的存储数据,您还应在哪里设置转换?

–克里斯·特拉弗斯(Chris Travers)
2014年3月23日在3:57