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

Emi*_*lás 65 mysql database performance database-design stored-procedures

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

我们仅使用存储过程来插入和更新业务模型实体.有几个表代表模型实体,我们将在那些存储过程insert/update中抽象它.

另一方面,我们可以从Model层调用insert和update,但不能在MySQL中调用,而是在PHP中调用.

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

PS:这是一个大多数阅读和高性能的网络项目是最重要的必要条件.

Boh*_*ian 72

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

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

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

在预先指定"高性能"时,建议小心.它往往会导致糟糕的选择而牺牲良好的设计,它会比你想象的更快地咬你.

使用存储过程是您自己的危险(来自那里的人,从不想回去).我的建议是像瘟疫一样避免它们.

  • 从项目开始两年.最后,我意识到我们在商店程序中封装了一点数据库功能的错误决定.再也不 :-).改变它并不是那么糟糕因为它很少,但在未来的项目中,数据库严格地会保存数据.我现在将这个答案标记为未来读者的好答案. (8认同)
  • @EmilioNicolás我确定这是因为你的架构很糟糕.我可以说,3年后,我更加爱上了我的一个基于SP的系统. (4认同)
  • @Bohemian,请问一个合适的[DBA](http://dba.stackexchange.com)值得他的盐,请放心[〜"不需要写SQL"](http://stackoverflow.com/questions/6276423/hibernate-memory-issues-defects)是一个久经考验的**神话**.它适用于小型应用程序和快速开发,但独立于数据库的持久性框架仅提供数据库提供的一小部分功能.您没有灵活性来调整查询. (4认同)
  • @EmilioNicolás不,我不会**建议在这种情况下使用它们.认为它是"好的设计"或者"让你的代码更清洁"是一种幻想.虽然这似乎是一个好主意,但事实并非如此.如果要封装该操作,请创建一个执行该操作的PHP函数并调用它.相信我,如果你不是绝对需要*,你会后悔存储过程. (3认同)
  • 我还要添加一些不使用存储过程的原因:使用标准部署工具不容易部署存储过程,并且大多数版本控制系统也不容易管理存储过程。 (2认同)
  • @pacerier的神话是你需要,甚至应该使用"db的所有功能".你可以避免编写查询并不是一个神话.我现在所从事的项目没有,我们遵循最佳实践.您的评论可能只适用于小型应用,但过去几年情况发生了变化:所有应用的最佳做法都是小型(谷歌微服务).仅供参考我曾经是一名DBA,也是一名优秀的DBA.问题是,当你拥有的只是一把锤子时,一切看起来都像钉子一样 - 请DBA做一些编码然后你得到一个存储过程,这是使用了错误的工具 (2认同)
  • @Bohemian,我们谈论的是一个成熟的系统[在**网络**](http://goo.gl/JwbFxY),而不是一个预阿尔法原型,其中开发速度比其他一切都重要。[性能是一个特性](http://blog.codinghorror.com/performance-is-a-feature/),这是使用 SP 的**原因**。部署和维护并不像你描述的那样是一个巨大的噩梦,它是原始数据输入和原始数据输出,与原始数据无关的东西不会在SP中编码。所谓的“噩梦”原始语言仅限于一个非常特定的区域,并且可以通过灵活的方式来解决。 (2认同)

dav*_*vek 30

与编程代码不同,它们:

  • 几乎不可能呈现SQL注入攻击(除非您正在 从过程中
    构造和执行动态
    SQL)
  • 作为标注的一部分,要求通过IPC发送的数据要少得多
  • 使数据库能够更好地缓存计划和结果集(由于其内部缓存结构,这对MySQL来说无疑是不那么有效)
  • 可以单独测试(即不作为JUnit测试的一部分)
  • 它们是可移植的,它们允许你使用特定于db的特性,抽象在一个过程名称后面(在代码中你被一般的SQL类型的东西所困)
  • 几乎从不比从代码调用的SQL慢

但是,正如波西米亚人所说的,还有很多缺点(这只是提供另一种观点).在决定什么对你最有利之前,你可能需要进行基准测试.

  • “作为标注的一部分,需要通过网络发送的数据要少得多”?请解释一下 POV,我同意 SQL 查询可能很长,如果写得不好或在一个查询中执行太多,但我相信传回的数据量与结果完全相同,结果应该是相同的结果?所以我们说的是几百字节pr的差异。DB 调用不同。在我看来,我们使用宽带的地方并不是“少得多”。少是真的,但“少得多”是过度夸大/主题。 (3认同)
  • 是的,我的意思是标注,而不是返回的内容:通常您会发出类似“call myProc(x,y,z)”这样的调用,它*可能*比复杂的 SQL 查询少得多的数据。并且根据您*可以*加起来的里程数。 (2认同)
  • 1. 不,SQL 注入攻击并非不可能,因为在实践中开发人员经常使用动态准备的查询。可以在没有 Sproc 的情况下使用参数化查询。2. 线路上的数据较少?也许是微不足道的,但在实践中几乎没有任何区别。3. MySQL 不会在 sprocs 中预编译或缓存计划。4. 是的,它们可以单独进行测试,但是如果您将查询分解为客户端上的可测试单元,它们也可以。 (2认同)
  • 使用存储过程的其他原因包括强类型和输入变量的输入大小限制。如果您在过程中有一个整数和一个日期参数,并且有人尝试使用任一输入变量注入 SQL,它就会失控。同样,如果您的 Web 服务器以某种方式受到威胁,如果 Web 服务器 db 用户只有执行权限,则攻击者将无法运行临时查询。此页面中有一些针对存储过程的相当蹩脚的论点,其中最糟糕的是“因为它很难”。将性能抛在脑后,仍然有充分的理由使用它们。 (2认同)

Seb*_*bas 14

As for performances, they have the potential to be really performant in a future MySQL version (under SQL Server or Oracle, they are a real treat!). Yet, for all the rest... They totally blow up competition. I'll summarize:

  • Security: You can give your app the EXECUTE right only, everything is fine. Your SP will insert update select ..., with no possible leak of any sort. It means global control over your model, and an enforced data security.

  • Security 2: I know it's rare, but sometimes php code leaks out from the server (i.e. becomes visible to public). If it includes your queries, possible attackers know your model. This is pretty odd but I wanted to signal it anyway

  • Task force: yes, creating efficient SQL SPs requires some specific resources, sometimes more expensive. But if you think you don't need these resources just because you're integrating your queries in your client... you're going to have serious problems. I'd mention the analogy of web development: it's good to separate the view from the rest because your designer can work on their own technology while the programmers can focus on programming the business layer.

  • Encapsulating business layer: using stored procedures totally isolates the business where it belongs: the damn database.

  • Quickly testable: one command line under your shell and your code is tested.

  • Independence from the client technology: if tomorrow you'd like to switch from php to something else, no problem. Ok, just storing these SQL in a separate file would do the trick too, that's right. Also, good point in the comments about if you decide to switch sql engines, you'd have a lot of work to do. You have to have a good reason to do that anyway, because for big projects and big companies, that rarely happens (due to the cost and HR management mostly)

  • Enforcing agile 3+-tier developments: if your database is not on the same server than your client code, you may have different servers but only one for the database. In that case, you don't have to upgrade any of your php servers when you need to change the SQL related code.

好吧,我认为这是我在这个问题上最重要的事情.我开发了两种精神(SP与客户端),我真的非常喜欢SP风格.我只是希望Mysql有一个真正的IDE为他们,因为现在它是有限的痛苦.

  • 关于*"来自客户的独立:如果明天你想从PHP切换到其他东西,没问题."*,如果需要更改的数据库层怎么办? (3认同)
  • 存储过程是穷人的微服务架构。让多个应用程序直接访问同一个数据库是真正的根本问题,同样可以通过存储过程或中间层访问层来解决。如果您接受这一点,那么就问问自己您更愿意构建和维护哪个 - 我会向您推荐已接受的答案。 (3认同)

Abh*_*hay 7

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

可能需要一段时间才能适应编程存储过程,因为它们有自己的语言和语法.但是一旦你习惯了它,你会发现你的代码非常干净.

在性能方面,如果您使用存储过程,它可能不会有任何重大收益.

  • 我不同意:1.您可以在没有存储过程的情况下保持您的查询组织.2.您可以执行查询批处理而无需存储过程; 3.存储过程不是在MySQL中预编译的.4.您可以在没有存储过程的情况下执行查询批处理(再次). (3认同)

Eny*_*ico 6

我会让我知道我的意见,尽管我的强硬可能与这个问题没有直接关系:

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

  • 你想得到什么.

您是在尝试批量操作还是在线操作?他们是完全交易的吗?这些行动有多复发?等待数据库的工作量有多重?

  • 你有什么才能得到它.

你有什么样的数据库技术?什么样的基础设施?您的团队是否接受过数据库技术的全面培训?您的团队是否能够更好地构建数据库诊断解决方案?

  • 得到它的时间.

没有秘密.

  • 建筑.

您的解决方案是否需要分发到多个位置?是您使用远程通信所需的解决方案吗?您的解决方案是在多个数据库服务器上工作,还是可能使用基于群集的架构?

  • Mainteinance.

需要多少申请才能更改?你有经过专门训练的个人维护解决方案吗?

  • 更换管理层.

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

  • 成本

使用一种或另一种策略实施该解决方案需要多少费用?

这些点的总体将推动答案.因此,在决定是否使用任何策略时,您必须关注每一点.有些情况下,存储过程的使用优于应用程序层管理的查询,而其他情况下,执行查询和使用基于应用程序层的解决方案时最好.

在以下情况下,使用存储过程往往更加充分:

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

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

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

希望这可能有助于任何人问自己什么是更好用.