前两天在知乎逛街, 看到有这么个话题, 顺手回答了下, 并分享在这里, 喜欢的话就一起讨论讨论吧.
几千行的 SQL 存储过程, 在比较老式的开发架构中常见, 起源于 C/S 年代. 通常是前端没有引入适当框架的设计, 而将所有的应用逻辑一股脑儿丢给数据库开发造成的. 当然这类设计的好处是上线快速, 极短时间便可拿下项目. 而弊端是扩展起来麻烦, 尤其数据库开发一旦跳槽之后, 留下的往往是看不懂的上古祖传代码, 此时再动刀扩展系统架构去支撑业务需求, 就显得吃力.
作为负责的数据库开发, 拿到这大几千行的 SQL 代码, 肯定是不能听之任之的.
首先, 理解代码.
越长的 SQL 越是要理解透彻. 开发为了省事 (项目负责人好好检讨) 凭着脑袋想到哪里, 写到哪里, 没有通盘考虑逻辑的合理性与程序的可读性. 有时候明明可以用一句 update 完成的操作, 有些开发笨拙的拆开了很多次去操作, 原因很可能是为了去记 log, 或者多个条件不懂得去归并. 前者是设计的错误, 后者是 SQL 本质思想的理解不到位.
在动手改代码之前, 一定要理解透彻代码, 不能操之过急. 往往像这类耦合度高的 SQL 应用逻辑, 好几个地方都在用, 改了之后不一定会给哪里造成 bug.
接着, 分拆代码.
在理解透彻业务逻辑的基础上, 对代码进行整块的分拆和聚合. 分拆和聚合的关键是控制事务. 主表一级的事务, 子表一级的事务, 是不是可以分开处理, 还是必须联合处理. 是否考虑用多个子存储过程来格式化代码, 显得更加易读, 逻辑上也更加易懂.
分拆代码的好处是可以让你快速掌握业务逻辑, 熟络每个业务关键点, 重点是培养对业务的敏感.
再接着, 改写代码.
当已经把代码段落按照业务逻辑分拆, 合并之后, 接下来就是在 SQL 细节层面做优化. 这时候首先要考虑 SQL 语言的特点, 集合化思想. 如果你有魔方, 可以拿起来看下, SQL 处理的是面以及面与面之间的关系.
如果要把红色的方块都选中, 有的开发朋友会将第 1, 2,3 行的筛选条件单独拿出来, 各自选出来之后再塞到临时表去做聚合, 而正确的做法是将 1, 2, 3 的筛选条件首先聚合, 归并, 使用一条 SELECT 或 Update 语句完成原本冗余的代码.
在命名规范, Magic Number, 低效率 SQL 编码上都要做严格审查, 防止代码的腐化. 不好的 SQL 代码习惯看到很多, 直接写 insert ... select * from /update/delete 都是要严格禁止的; 在大并发的系统中, 使用临时表装载大量数据来满足报表需求, 也是要适可而止的; OLTP 要和 OLAP 严格分开库, 这种并存一库的架构至今在很多单位还存在着.
最后, 保存代码.
任何代码都需要进 Source Code Version Control. 无论是 Git/SVC/TFS, 针对遗留代码, 新增代码都要进行完整的源代码版本控制, 做到有源可溯.
为什么会有这大几千行的 SQL 代码呢, 我猜原因有 2 :
1 项目赶, 时间紧, 一切 以上线为重. 自以为上线后会修改自己的代码, 往往不大可能. 就算你有心, 后面的项目需求也会把你的积极性消磨殆尽. 一旦项目结束, 你跳槽, 薪水翻倍了, 再回头就没有机会了.
2 写 SQL 不写草稿. 这个习惯可能大部分人都会觉得很奇怪, 写代码还写草稿? 其实代码和写作一样, 都是一种表达. 村上春树写小说都打草稿, 还修改不止一两遍. 博尔赫斯等大文豪, 对于修改是非常执着的. 没有四五遍修改, 都不好意思见人. 我们有些程序员就是太贪, 太急, 潦草完事, 从不往回找找感觉. 看到业务就想接, 这样不是不好, 但总结归纳本就是一门提高效率的学问, 举一反三手艺才能稳步提高.
有多少朋友, Pivot 总是写得不顺手, 归根结底就是对写过的代码不总结, 而写草稿, 恰恰给你一个总结的过程.
来源: https://juejin.im/post/5c67621851882562611290ff