程序员过关斩将你为什么还在用存储过程

45次阅读

共计 1627 个字符,预计需要花费 5 分钟才能阅读完成。

存储过程

存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的 SQL 语句集,它存储在数据库中,一次编译后永久有效,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象。

优势
  1. 可以减少程序在调用 DB 时候的信息传输量(其实减少的只有 Request 的时候)
  2. 存储过程是预先优化和预编译的,节省每次运行编译的时间,所以一般情况下认为存储过程的性能是优于 sql 语句的。
  3. 对调用者可以隐藏数据库的复杂性,将数据组装的过程封装。
  4. 参数化的存储过程可以防止 SQL 注入式攻击,而且可以将 Grant、Deny 以及 Revoke 权限应用于存储过程。
  5. 如果业务开发中,数据人员和业务代码人员是分离的,业务人员可以不用关心数据,直接调用存储过程,更加面向分层开发设计理念。
劣势
  1. 存储过程这种“一次优化,多次使用”的策略节省了每次执行时候编译的时间,但也是该策略导致了一个致命的缺点:可能会使用错误的执行计划。
  2. 存储过程难以调试,虽然有些 DB 提供了调试功能,但是一般的账号根本就没有那种权限,更何况线上的数据库不可能会给你调试权限的,再进一步就算能调试效果也比程序的调试效果要差很多。
  3. 可移植性差,当碰到切换数据种类的时候,存储过程基本就会歇菜。
  4. 如果业务数据模型有变动,存储过程必须跟着业务代码一起更改,如果是大型项目,这种改动是空前的,是要命的。

不推荐存储过程

以上存储过程的优缺点,你随便一下网络就可能查到,表面看来存储过程的优势还是不少的,这也说明为什么老一辈程序员有很多喜欢写存储过程。但是随着软件行业业务日益复杂化,存储过程现在在复杂业务面前其实有点有心无力。

菜菜在业务中并不推荐使用存储过程, 辩驳请留言

  1. 采用存储过程操作数据在网络数据量传输上确实比直接使用 sql 语句要少很多,但这通常并不是操作数据系统性能的瓶颈,在一次操作数据的过程中,假设用时 100 毫秒,采用存储过程节省数据传输时间 0.5 毫秒(就算是 5 毫秒),我觉得这点时间基本可以忽略。
  2. 存储过程是只优化一次的,这有时候恰恰是个缺陷。有的时候随着数据量的增加或者数据结构的变化,原来存储过程选择的执行计划也许并不是最优的了,所以这个时候需要手动干预或者重新编译了,而什么时候执行计划不是最优的了这个平衡点,预先无法知晓,这就导致了有些应用突然会变慢,程序员处于懵逼的状态。
  3. 存储过程确实可以对调用方隐藏数据库的细节,但是这种业务代码人员和数据库设计人员是两个团队的情况又有多少呢,如果真是两个团队,那业务就需要两个团队来理解和沟通,我想沟通的成本也一定很高,而且分歧更容易产生。

菜菜认为数据库就应该做它最擅长的事情:存储相关。我不止一次的看过把业务写在存储过程的情况,程序代码层面真是薄薄的贫血层,就是一个数据的透传。我不赞同这种写法,因为我就接手过这样的程序,令我头疼的不是业务,而是看着好几千行的存储过程熟悉业务,关键还没有调试的权限(线上更不能调试)。

一个业务系统的设计往往需要你从数据库的层面抽离出来,把主要精力放在业务模型的设计上,在程序层面体现业务逻辑,而不是把业务逻辑都交给数据层面的管理者。前几天我排查过一个“Bug”:存储过程是输入参数是一个主键 id 的列表字符串,长度居然是 nvarchar(max),主要功能是根据 id 列表查询数据。我想说的是就算你是 max 的长度,也有超长的可能性发生,因为业务方传输什么参数,参数什么长度是你 DB 无法控制的,所以这类的业务一定要放在程序中做处理,而不是怀着侥幸心里丢给 DB。

如果是抱着存储过程性能高的心态的话,我到时觉你这是误入歧途,菜菜认为存储过程从来都不是提高性能的关键,反而系统的架构,缓存的设计,数据一致性更是系统关键问题。

存储过程通常是一种解决方案,但是通常情况下不是唯一的解决方案,在选择存储过程作为方案前,请确保他们是正确的选择。

最后秀一波存储过程吧


添加关注,查看更精美版本,收获更多精彩

正文完
 0