MySQL存储过程使用或不使用它们


67

我们正处于一个新项目的开始,我们真的想知道是否应该在MySQL中使用存储过程。

我们将仅使用存储过程来插入和更新业务模型实体。有几个表代表模型实体,我们将在那些存储过程的插入/更新中对其进行抽象。

另一方面,我们可以从Model层调用插入和更新,但是不能在MySQL中而是在PHP中。

根据您的经验,哪个是最佳选择?两种方法的优点和缺点。就高性能而言,哪一个最快?

PS:这是一个大多数阅读的Web项目,而高性能是最重要的要求。

Answers:


78

与实际的编程语言代码不同,它们:

  • 不可移植(每个数据库都有自己的PL / SQL版本。有时同一数据库的不同版本不兼容-我已经看到了!)
  • 不容易测试-您需要 真实的(dev)数据库实例来对其进行测试,因此几乎不可能对作为构建一部分的代码进行单元测试
  • 不容易更新/发布-您必须删除/创建它们,即修改生产数据库以释放它们
  • 没有库支持(为什么别人有时写代码)
  • 不易与其他技术集成(尝试从中调用Web服务)
  • 他们使用的语言与Fortran一样原始,因此难以完成有用的编码,因此很难表达业务逻辑,即使通常这是他们的主要目的
  • 不提供调试/跟踪/消息记录等功能(某些数据库可能支持此功能-虽然我没有看到)
  • 缺乏像样的IDE来帮助语法和链接到其他现有过程(例如,像Eclipse的Java那样)
  • 熟练的编码人员比应用编码人员稀有且昂贵
  • 它们的“高性能”是一个神话,因为它们在数据库服务器上执行通常会增加数据库服务器的负载,因此使用它们通常会降低最大事务吞吐量
  • 无法有效共享常量(通常通过在过程中创建表并查询表来解决-非常低效)
  • 等等

如果您有一个非常特定于数据库的操作(例如,用于维护数据库完整性的事务内操作),或者使您的过程保持原子性和简单性,那么也许您可以考虑使用它们。

在预先指定“高性能”时,建议小心。它通常会导致错误的选择,以牺牲好的设计为代价,并且比您想的要早得多。

使用存储过程的后果自负(曾经去过那里并且从不想回头的人)。我的建议是避免它们像瘟疫一样。


4
@EmilioNicolás不,我建议在这种情况下使用它们。认为它是“好的设计”或“将使您的代码更整洁”是一种幻想。尽管这似乎是个好主意,但事实并非如此。如果要封装该动作,请创建一个执行该动作的PHP函数并调用该函数。相信我,如果您并非绝对要这样做,那么如果您沿着存储过程走下去,您将后悔。
波希米亚

9
从项目开始两年。最后,我意识到我们做出的错误决定是我们在存储过程中封装了一些数据库功能。再也不 :-)。更改它并不是很糟糕,因为它很少,但是在将来的项目中,数据库将严格保存数据。我现在将此答案标记为对未来读者的好答案。
EmilioNicolás2014年

5
@EmilioNicolás我敢肯定这是因为您一开始的体系结构很差。我可以说,三年后,我更加爱上了我的一个基于SP的系统。
塞巴2014年

3
我还要补充一些不使用存储过程的原因:使用标准部署工具不容易部署存储过程,并且大多数版本控制系统也不容易管理存储过程。
Martijn 2015年

4
@Bohemian,只要问一个适当的DBA值得付出什么,就放心〜“不需要编写SQL”是一个久经考验的神话。这对小型应用程序和快速开发很有好处,但是与数据库无关的持久性框架仅提供数据库提供的功能的一小部分。您调整查询的灵活性为零。
Pacerier

34

与编程代码不同,它们:

  • 使得SQL注入攻击几乎不可能(除非您正在
    动态构建和执行
    从过程SQL)
  • 要求通过IPC发送的数据少得多作为标注部
  • 使数据库能够更好地缓存计划和结果集(由于其内部缓存结构,这对MySQL而言效果不明显)
  • 可以很容易地进行隔离测试(即不作为JUnit测试的一部分)
  • 在它们允许您使用特定于数据库的功能的意义上是可移植的,这些功能被抽象在过程名称之后(在代码中,您陷于通用SQL类型的东西中)
  • 几乎从未比从代码调用的SQL慢

但是,正如波西米亚人所说,也有很多弊端(这只是提供了另一个观点)。在决定最适合自己的东西之前,您可能必须先进行基准测试。


2
“需要更少的数据作为标注的一部分通过电线发送”?请解释一下POV,我同意SQL查询可以很长,如果写得不好或在一个查询中执行太多,但是我相信回传的数据量与结果应该完全一样吗?因此,我们谈论的是几百个字节的差异。DB调用有所不同。在我心目中使用宽带的地方并不是“远远”。少是正确的,但“少得多”是过度夸大/主题。
BerggreenDK

2
是的,我的意思是标注,所返回不算什么:通常你会发出类似“呼叫MYPROC(X,Y,Z)”,它的呼叫可以比一个复杂的SQL查询数据逊色得多。并取决于您可以累积的里程。
2011年

2
1.不,SQL注入攻击并非不可能,因为实际上开发人员经常使用动态准备的查询。可以在不使用Sproc的情况下使用参数化查询。2.电线上的数据更少?也许微不足道,但实际上几乎没有任何区别。3. MySQL不会在存储过程中预编译或缓存计划。4.是的,它们可以单独进行测试,但是如果您将查询分解为客户端上的可测试单元,那么它们也可以。
MarkR 2011年

2
使用存储过程的其他原因包括强类型输入和输入变量的输入大小限制。如果您在过程中有一个整数和一个日期参数,并且有人尝试使用这两个输入变量来注入SQL,则它将失控。同样,如果您的Web服务器受到某种程度的破坏,如果Web服务器数据库用户仅具有执行权限,攻击者将无法运行即席查询。此页面中有一些针对存储过程的相当la脚的参数,最糟糕的是“因为很难”。抛开性能,仍然有充分的理由使用它们。
尼尔·戴维斯

1
两件事,@ MarkR。1.戴维克说“几乎不可能”。2.整个线上的数据量的“琐碎”差异取决于查询的大小和返回的数据量。
布赖恩

17

至于性能,它们有潜力在将来的MySQL版本中真正发挥作用(在SQL Server或Oracle下,它们是真正的享受!)。然而,对于其他所有...他们完全破坏了竞争。我总结一下:

  • 安全性:您只能为您的应用赋予EXECUTE权限,一切都很好。您的SP将插入更新选择...,而不会发生任何形式的泄漏。这意味着对模型的全局控制以及强制的数据安全性。

  • 安全性2:我知道这种情况很少见,但有时php代码会从服务器中泄漏出去(即对公众可见)。如果其中包含您的查询,则可能的攻击者知道您的模型。这很奇怪,但我还是想发信号

  • 工作组:是的,创建高效的SQL SP需要一些特定的资源,有时甚至更昂贵。但是,如果您认为仅仅因为将查询集成到客户端中就不需要这些资源,那将会遇到严重的问题。我提到过Web开发的类比:将视图与其他视图分开是很好的,因为您的设计师可以使用自己的技术,而程序员可以专注于对业务层进行编程。

  • 封装业务层:使用存储过程可以完全隔离其所属的业务:该死的数据库。

  • 可快速测试:外壳下有一个命令行,您的代码也经过了测试。

  • 独立于客户端技术:如果明天您想从php切换到其他版本,那没问题。好的,只需将这些SQL存储在单独的文件中也可以解决问题,是的。另外,在注释中,如果决定切换sql引擎,您将有很多工作要做。无论如何,您必须有充分的理由这样做,因为对于大型项目和大型公司,这种情况很少发生(主要是由于成本和人力资源管理)

  • 实施3层以上的敏捷开发:如果您的数据库与客户端代码不在同一服务器上,则您可能拥有不同的服务器,但数据库只有一台服务器。在这种情况下,当您需要更改与SQL相关的代码时,无需升级任何php服务器。

好的,我认为这是我必须在该主题上说的最重要的事情。我本着两种精神(SP与客户)发展的,我真的非常钟爱SP风格。我只是希望Mysql为他们提供一个真正的IDE,因为现在有限的屁股上有点痛苦


3
关于“独立于客户端:如果明天您想从php切换到其他东西,没问题。” ,如果需要更改的是DB层怎么办?
和平者

2
存储过程是穷人的微服务体系结构。真正的根本问题是让多个应用程序直接访问同一数据库,而存储过程或中间层访问层同样可以解决这个问题。如果您接受,则只问自己自己想建立和维护的是哪一个-我将带您回到已接受的答案。
HonoredMule

1
“任务组”是一种错觉-编写高效的SQL代码需要特定的技能,而不管该代码是用存储过程还是应用程序代码编写。
布赖恩

8

存储过程很好用,因为它们可以使您的查询井井有条,并允许您一次执行批处理。存储过程通常是快速执行的,因为它们是预编译的,与每次运行时都会编译的查询不同。这在数据库位于远程服务器上的情况下具有重大影响;如果查询在PHP脚本中,则应用程序与数据库服务器之间存在多种通信-查询被发送,执行并返回结果。但是,如果使用存储过程,则只需要发送一个小的CALL语句,而不是发送大而复杂的查询。

由于存储过程具有自己的语言和语法,因此可能需要一段时间才能适应对存储过程进行编程。但是,一旦习惯了,就会发现您的代码确实很干净。

就性能而言,如果不使用存储过程,则可能不会有太大的收获。


3
我不同意:1.您可以在不存储过程的情况下组织查询。2.您可以在没有存储过程的情况下执行查询批处理;3.存储过程未在MySQL中预编译。4.您可以再次执行没有存储过程的查询批处理。
MarkR 2011年

1
@MarkR:我同意,但我并不是要说,除了存储过程以外,没有其他方法可以组织您的查询或运行批处理查询。我想我不知道MySQL存储过程没有预编译,这很奇怪,但是感谢您的帮助。
阿贝(Abhay)

1
@Abhay,您是否不应该删除有关预编译的误导性信息?
Pacerier

6

尽管我的强项可能与问题没有直接关系,但我会告诉我我的意见:

与许多问题一样,有关使用存储过程或应用程序层驱动的解决方案的答复依赖于推动整体工作的问题:

  • 你想得到什么。

您要执行批处理操作还是在线操作?他们完全交易吗?这些手术的复发频率如何?数据库等待的工作量有多大?

  • 您拥有什么才能得到它。

您拥有什么样的数据库技术?什么样的基础设施?您的团队是否接受过数据库技术方面的全面培训?您的团队是否更有能力构建与数据库无关的解决方案?

  • 时间到了。

没有任何秘密。

  • 建筑。

是否需要将您的解决方案分发到多个位置?使用远程通信是否需要您的解决方案?您的解决方案可在多台数据库服务器上运行,还是可能使用基于集群的体系结构?

  • 维护。

需要更改多少应用程序?您是否经过专门培训以维护解决方案?

  • 更换管理层。

您是否看到您的数据库技术将在短,中,长时间内发生变化?您看到需要频繁迁移解决方案吗?

  • 成本

使用一种或另一种策略来实施该解决方案将花费多少?

这些点的整体将推动答案。因此,在决定使用或不使用任何策略时,您必须注意每一点。在某些情况下,使用存储过程比在应用程序层管理的查询中更好,而在其他情况下,执行查询和使用基于应用程序层的解决方案则是最佳选择。

在以下情况下,使用存储过程往往更为适当:

  1. 您的数据库技术没有在短期内发生变化。
  2. 您的数据库技术可以处理并行化的操作,表分区或任何其他将工作负载划分为几个处理器,内存和资源(集群,网格)的策略。
  3. 您的数据库技术已与存储的过程定义语言完全集成在一起,也就是说,数据库引擎内部提供了支持。
  4. 您有一个开发团队,他们不害怕使用过程语言(第三代语言)来获得结果。
  5. 您想要实现的操作是内置的或在数据库内部受支持的(导出为XML数据,通过触发器,计划的操作等适当地管理数据完整性和一致性)。
  6. 可移植性不是一个重要的问题,您也不希望在短时间内对组织进行技术更改,即使这样做也不可取。通常,可移植性被应用程序驱动和面向分层的开发人员视为一个里程碑。从我的角度来看,当不需要将应用程序部署到多个平台上时,可移植性就不是问题,而在没有理由进行技术更改或迁移所有组织数据的工作量大于进行更改的好处。通过使用应用程序层驱动的方法(可移植性),您可以赢得的收益是,您可能会失去从数据库中获得的性能和价值(为什么要花费数千美元才能获得不超过60英里/小时的法拉利, ?)。
  7. 性能是一个问题。第一:在某些情况下,使用单个存储过程调用可以比从另一个应用程序多次请求数据获得更好的结果。此外,您需要执行的某些特性可能内置在数据库中,并且在工作负载方面,使用它的成本较低。使用应用程序层驱动的解决方案时,必须考虑建立数据库连接,调用数据库,网络流量,数据包装(即,使用Java或.NET时)的相关成本。使用JDBC / ADO.NET调用,因为您必须将数据包装到代表数据库数据的对象中,因此,当数据来自外部时,实例化在处理,内存和网络方面具有相关的成本)。

在以下情况下,应用程序层驱动的解决方案的使用往往更为充分:

  1. 可移植性是一个重要的问题。
  2. 应用程序将部署到只有一个或几个数据库存储库的多个位置。
  3. 您的应用程序将使用繁重的面向业务的规则,这些规则与基础数据库技术无关。
  4. 您一定要根据市场趋势和预算来更改技术提供商。
  5. 您的数据库没有与调用该数据库的存储过程语言完全集成。
  6. 您的数据库功能有限,并且您的要求超出了使用数据库技术可以实现的范围。
  7. 您的应用程序可以支持外部调用固有的代价,它是基于事务的,并且具有特定于业务的规则,并且必须将数据库模型抽象为用户的业务模型。
  8. 并行化数据库操作并不重要,而且您的数据库没有并行化功能。
  9. 您拥有一个开发团队,该团队没有经过良好的数据库技术培训,并且可以使用基于应用程序驱动的技术来提高生产率。

希望这可以对任何问自己一个更好的人有用。


3

我建议您不要使用存储过程:

  • 他们在MySQL中的语言很烂
  • 无法将数组,列表或其他类型的数据结构发送到存储过程中
  • 存储过程永远不会更改其接口。MySQL不允许命名或可选参数
  • 这使部署新版本的应用程序变得更加复杂-假设您有10台应用程序服务器和2个数据库,那么您首先更新哪个?
  • 您的开发人员都需要学习和理解存储过程的语言-这非常糟糕(正如我之前提到的)

相反,我建议创建一个图层/库并将所有查询放入其中

您可以

  • 更新此库并将其与您的应用程序一起发送到您的应用程序服务器上
  • 具有丰富的数据类型,例如数组,结构等
  • 对这个库而不是存储过程进行单元测试。

关于性能:

  • 使用存储过程将降低应用程序开发人员的性能,这是您关心的主要事情。
  • 在复杂的存储过程中识别性能问题极其困难(对于普通查询而言,这要容易得多)
  • 您可以通过网络在单个块中提交查询批处理(如果启用了CLIENT_MULTI_STATEMENTS标志),这意味着如果没有存储过程,您将不会再有任何延迟。
  • 应用程序端代码的可伸缩性通常比数据库端代码更好

1
你是怎么得到的-2
Pacerier,2015年

这是理智的答案,公认的答案也是正确的,但这个感觉就像是一个有经验的人的智慧
Rakesh Waghela

3

如果您的数据库很复杂,而不是带有响应的论坛类型,但是真正的仓库SP肯定会受益。您可以在那里使用所有业务逻辑,没有一个开发人员会关心它,他们只是称呼您的SP。我一直在这样做,连接15个以上的表并不有趣,您不能向新开发人员解释。

开发人员也无权访问数据库,太好了!剩下的交给数据库设计人员和维护人员。如果您还决定要更改表结构,则可以将其隐藏在界面后面。n层,记得吗?

高性能和关系型数据库并不能同时使用,即使MySQL InnoDB的运行速度也不慢,现在应该将MyISAM抛在窗外。如果您需要Web应用程序的性能,则需要适当的缓存,内存缓存或其他缓存。

在您的情况下,因为您提到了“ Web”,所以我不会使用存储过程,如果它是数据仓库,那么我肯定会考虑(我们在仓库中使用SP)。

提示:既然您提到了Web项目,尽管有关于nosql的解决方案?另外,您需要一个快速的数据库,为什么不使用PostgreSQL?(试图在这里倡导...)


1
这篇文章非常混乱:1.将DWH与OLAP工作负载混淆了。2.高度自以为是。3.没有任何证据或引证就性能问题争论不休。4.它提出了没有理由的其他论点(例如,“ SP肯定会受益”而不说如何做)。同样,发布者显然从来没有在使用存储过程的应用程序的真正开发团队中工作过-这些过程实际上并没有由任何神奇的“数据库团队”维护,这取决于他们。
MarkR 2011年

马克,我想说的是个人经历。我确实在一个真正的开发团队中工作,并且在大型数据库方面我同时拥有MySQL和PostgreSQL的经验。我们在团队内部使用存储过程取得了巨大的成功,这有助于在复杂的数据库上工作。
R. van Twisk

@ries,即使对于普通应用程序,使用10个以上的表进行联接实际上并不罕见(假设db是为高规格化而构造的)。顺便说一句,“真正的仓库”是什么意思?你有一些例子吗?
Pacerier'1

2

我以前使用过MySql,对sql的理解充其量是不好的,我花了相当多的时间使用Sql Server,我清楚地将数据层和应用程序层分开了,我目前正在照顾一台0.5 TB的服务器。

有时我不使用ORM感到沮丧,因为使用存储过程的开发确实非常快,而且速度慢得多。我认为使用ORM可以加快我们的许多工作。

当您的应用程序达到临界质量时,ORM性能将受到损害,一个编写良好的存储过程将使您更快地获得结果。

作为性能的一个示例,我在一个应用程序中收集了10种不同类型的数据,然后将其转换为XML(在存储过程中进行处理),我只对数据库进行了一次调用,而不是10。

sql非常擅长处理数据集,令我感到沮丧的是,当我看到有人从原始格式的sql中获取数据并使用应用程序代码遍历结果并对其进行格式化和分组时,这确实是一种不好的做法。

我的建议是充分学习和理解sql,您的应用程序将真正受益。


您提到的迭代过程是我在应用程序逻辑中看到的很多东西。没想到您可以在MySQL中做同样的事情,并且在应用程序中的每个循环都很慢且不必要。
chuckjones242 '16

2

这里的许多信息使人们感到困惑,软件开发是一种进化。我们20年前所做的并不是现在的最佳实践。在使用经典客户端服务器的日子里,除了SP之外,您什么都做不到。

如果您是一个大型组织,您将使用多层甚至SP,那么这绝对是课程的成功之选,但是您将不太在乎它们,因为有专门的团队将它们整理出来。

相反的是,我发现自己试图快速完善Web应用程序解决方案,完善了业务需求,让开发人员(远程由我来处理)完善页面和SQL查询非常快,我定义了数据库结构体。

但是,复杂性在不断增长,并且没有提供API的简便方法,我希望使用SP来包含业务逻辑。我认为它运行良好且明智,我控制了它,因为我可以构建逻辑并为离岸开发人员提供简单的结果集以构建前端。

如果我发现我的软件取得了巨大的成功,那么将有更多的关注点分离,并且网络的不同实现将会出现,但是目前SP是完美的。

您应该知道所有可用的工具集并与之匹配是明智的。除非您要构建一个企业系统,否则快速简单是最好的。


1

我建议您远离数据库特定的存储过程。

我经历了很多项目,他们突然想要切换数据库平台,而SP中的代码通常不是很容易移植=额外的工作和可能的错误。

存储过程的开发还需要开发人员直接访问SQL引擎,而通常情况下,项目中的任何人都可以通过代码访问来更改正常的连接。

关于您的模型/层/层的想法:是的,坚持下去。

  • 网站调用业务层(BL)
  • BL调用数据层(DL)
  • DL调用任何存储(SQL,XML,Webservice,套接字,文本文件等)。

这样,您可以保持各层之间的逻辑级别。如果和仅当DL调用似乎很慢时,如果您突然需要将数据库转移到一个全新的平台上,就可以开始使用存储过程,但是可以将原始的非SP代码保留在某个地方。有了业务中所有的云托管,您将永远不知道下一个数据库平台将是什么...

出于同样的原因,我密切关注Amazon AWS。


1
因为它是正确的说SP是具体的,因此不便于携带,我希望在IT DPT构建一个完整的DB包是某些不改变的是RDBMS明天上午...
Sebas

1

我认为关于数据库存储的查询有很多错误信息。

如果您要对数据进行许多静态查询,则建议使用MySQL存储过程。尤其是当您要将事物从一张桌子移动到另一张桌子时(例如,出于某种原因从活动桌子移动到历史桌子)。当然,这样做有个缺点,那就是必须单独记录更改的日志(理论上,您可以创建一个表,该表仅保存DBA更新的存储过程的更改)。如果您有许多不同的应用程序与数据库连接,特别是如果您说有一个用C#编写的桌面程序和一个用PHP编写的Web程序,那么将某些过程存储在数据库中可能是更有利的,因为它们与平台无关。

该网站上有一些有趣的信息,您可能会觉得有用。

https://www.sitepoint.com/stored-procedures-mysql-php/

与往常一样,首先构建沙盒,然后进行测试。


-2

尝试从框架更新实时系统上的100,000,000条记录,然后让我知道它的运行方式。对于小型应用程序来说,SP不是必需的,但对于大型的严肃系统而言,它们是不二之选。


我认为您的答案无论如何都不能帮助用户解决查询。
Abhinav
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.