本文转载自微信公众号《关于SQL》,作者Lenis。转载本文,有关SQL公众号请联系。几千行SQL代码很常见,永不过时!经历过大大小小的MIS系统,小到几个人用的协作系统,到几十人用的OA系统,到上千人用的MES/ERP系统,再到电商系统在数百万人看来,半个世纪以来(从1970年代后期开始),存储过程的影子从未淡出它的战场。我们几个SQL老玩家经常吹嘘SQL是半衰期最长的编程语言。玩它不用担心失去工作。之前写过如何阅读和反汇编千行SQL存储过程。具体可以参考以下两篇文章:如何提高阅读SQL源码的乐趣如何写一个千行SQL存储过程(有代码规范)两篇文章分别提到了四个步骤:看懂代码,拆分代码,重写代码并保存代码。我按照业务的要求,拆解了无数代码,从几千行减少到20%,组装了无数代码,从几百行到几千行。我见过最长的SQL代码超过5000行,没有什么可以简化的,还是实事求是吧。人分而合,生活密码亦然。但装拆不是逆过程!就像我们能看懂村上春树的小说《且听风吟》和《刺杀骑士团长》,却写不出来,写得那么好。当然,那是村上赖以谋生的技能。老头子写了三十多年的小说,我们可能一部都没看完,没法比较。既然如此,在我们赖以生存的SQL阵营中,这个吃饭的本事就得好好磨练了。以下感悟来自于我在实战中的真实想法,趟过无数坑,总结出几个我认为非常有用的经验。了解业务,快速实施,重构测试,版本控制,审核记录1.了解业务,你肯定不会写没有业务逻辑的代码。充分理解业务逻辑对你有两个好处:一是编写可执行和可扩展的代码;二是积极了解业务,有利于职业发展。第一个好处是不言而喻的。写代码写出颈椎病的程序员一定要意识到代码的可扩展性,可以节省去医院的时间,多霸屏几次。例如,代码的可扩展性如何?例如,产品的价格。电子商务时代,产品价格具有明显的膨胀性。也就是说,今天是这个价格,明天又是另一个价格。电商时代,双11、双12都贴上了商业促销标签,对产品价格提出了很高的要求。此时,当你设定一个产品价格时,你会如何设计呢?是直接在原价的基础上更新,还是新建一个栏目承载新的价格?此类价格设计将直接影响电子商务促销活动分析的结果。如果我们直接更新价格,我们将失去与历史销量进行比较的便利。如果我们不记录单价和订单,我们将失去与历史的比较。从设计的角度来看,这是一个失败,失去了灵活性和可扩展性。这样的设计,每次价格变化,都需要更新大量的产品价格表和销售历史表,对现有的业务活动造成干扰。更好的是,为价格添加有效使用日期。比如这个价格在这个期间有效,另一个价格在促销阶段。并使用视图(view)提供产品数据,而不是直接从原始表中读取数据,失去了中间业务的缓冲。Kimball对这类业务的理解最有说服力。他的《Dimensional modeling》(《维度建模》)总结了几十个行业的通用设计模型,堪称数据模型行业的设计模式。第二个好处并不是每个人都意识到。虽然SQL是职业生涯最长的编程语言,比如和它一起出现的VFP,90后大概闻所未闻,但显然没有人愿意一辈子鼓捣CRUD。吃鸡同学放下你的iPhone13,家里有地雷没人提你。了解业务使您成为整个应用程序生态系统中不可或缺的一部分。信息化的目的不是写代码,最终目的是盈利。我想二爷(秋月)肯定能同意我的看法。说到这里大家就明白了,我们写SQL就是熟悉一个行业的数据流向和资金流向,做好市场的监控。那么还有谁比我们更了解一家公司的真实经营情况呢,不,一点也不知道。前提是你得做对,懂。当你只是把自己定位成一个coder的时候,真的有点大材小用了。你可以追求SQL的技能,但最终业务会支持你走得更远。你永远不可能是20岁或30岁。总有一天你会被期望拥有发展事业的能力,并拥有可以指导后代的经验。在这一点上,技术经验是非常通用的。甚至可能在身手上完全不如年轻人。唯一能给你权威的是你在其他方向上能走多远。2.快速实施很多朋友(包括我)有时候遇到需求也会苦思冥想。他们要的是一口气把SQL从头到尾写得完整自如。“哇”和漂亮的回车声是屏住呼吸的期待。可现实无数次地打了我的脸!越是有这种想法,我写一点点的时间就越长。总觉得这个地方不好,那个地方不好。这里的变量名不够鲜明,那里的Pivot不够优化。结果经常在那里纠结一个早上什么都没做。你有类似的经历吗?村上春树、海明威和博尔赫斯并不孤单。他们总是第一次写小说,然后写下来。一旦卡住了,他们就把它搁置起来,明天继续。大家可以猜到我这里要说的攻略。先来实现业务,再说命名规则、变量声明、事务控制、性能优化。编写CRUD,提交初稿,存档,Over!作家要等灵感来写,怎么能看到那么多有趣的故事。同样,我们如何在没有考虑所有事情之前编写代码。想到一个数据流,用到哪些表,直接写就可以了。等啊等啊,心里慌了,写啊写啊,念头来了。例如,你需要多少时间来实现下面的CRUD?如果一开始你盯着这张图,你就开始思考如何记录日志,查看用户是否单点登录,用户是否使用促销券,如何撤单,是否控制并发,那么无疑给自己增加了很多戏份,很多无形的压力让你自己做不来。越想越有上进心,越觉得自己做不到。在你迷茫的时候,如果有个会议,有个热闹的消息,一旦你离开,就很难回到你的宏伟蓝图。该怎么办?此时,你要做的第一件事就是快速实现这些关键点的增删改查代码。例如购物车的增删改查、用户登录、填写订单信息、报表等。等到这一系列操作完成,熟悉了整个业务流程和数据流程之后,再进行第二次追加功能。3.重构和测试最后,在第一个版本中,您添加了额外的功能。实现了大部分业务功能。这个时候可以投稿checkin你的code吗?不!如果你认为这个时候可以高枕无忧,那你会死得很惨的。你会变成别人口中的“猪一样的队友,出轨……”在《巴黎评论》中,村上春树提到自己的小说经常要修改4-5次才投稿,编辑还要修改。我们传一次的SQL就免检了?现在是测试您真正的SQL技能和编码质量的时候了。然后检查命名规则、变量声明、事务控制和性能优化。你会发现还有很多事情要做。例如嵌套多次。我知道很多朋友会这样写:SELECT*FROM(SELECT*FROM(SELECT*FROMBASE)T1)T2如果继续让这样的代码存在于你的项目中,项目很快就会失控。.至少,第一次阅读代码,我们需要完成格式的美化:SELECT*FROM(SELECT*FROM(SELECT*FROMBASE)T1)T2这样即使代码不够优雅,其他人也不会阅读此代码时会受到诅咒。第二次重构时,可以考虑减少嵌套,或者增加CTE包嵌套:;WITHBASE_TABLEAS(SELECT*FROMBASE)SELECT*FROMBASE_TABLE又比如unpivot之后的聚合:我们可以在开头写unpivot很好,然后嵌套一个聚合层,如下:SELECTConvert(Date,OrderDate)asOrderDate,Sum(Amount)ASAmountFROM(SELECTOrderDate,Unp.AmountASAmountFROMFctOrderAmountsUNPIVOT(AmountforTypein(Shipment,UnitCost))Unp)RSLGROUPBYConvert(Date,OrderDate)所以一看就很清楚,但是信息量大,结构复杂,中间可能还有其他字段或者Join,导致复杂,那我们至少要再简化一下:SELECTOrderDate,Sum(Unp.Amount)ASAmountFROMFctOrderAmountsUNPIVOT(AmountforTypein(Shipment,UnitCost))UnpGroupbyUnp.Amount是另一个例子。有很多关键步骤。实际上,我们可以拆分它们,直到一个存储过程完成一个功能。这样不仅完成了代码的简化,还提供了可重用的接口。也可以让群里的小伙伴们齐心协力。一石三鸟,这样的事情,值得花时间。最后,在所有测试分支上运行测试并提交!4.版本控制如果你的团队没有git、SVN、TFS源代码版本控制,赶快搞一个吧。没有自动化部署工具,自己想办法做一个。2021年了,别偷懒了。为什么需要版本控制?当你第一次开始编程时应该知道这一点。比如你觉得越来越讨厌现在的自己,或者是太胖了,或者是太弱了,或者是太没文化了,就想穿梭,回到15、16岁,重新开始.你会告诉自己多吃蔬菜和水果,坚持每天运动,坚持每天看书、写字、看报。虽然我们不能实现遍历,但是代码可以。使用上面提到的软件可以帮助我们回到我们想要重新开始的版本并更正代码。5、审核记录做了以上4步,有公司项目的说明。但是做到这一步,就是要对自己有一个交代。就像刚才重构的时候,CTE、UNPIVOT、代码简化的策略可能会被灵感或者责任感淹没。反正你当时就想到了,但是如果你不及时记录下来,时间久了你可能会忘记自己曾经做过这么神奇的操作。所以,你辛苦写了一段很长的代码之后,一定要通过review记录下来,放到你的博客,github等,以后遇到类似情况,却又想不通怎么解决的时候,您可以随时将其取出使用。看过很多这样的代码示例,关注微信公众号【关于SQL】,回复【5000】,就可以看到这些真实的源码。编写SQL代码的质量当然远不止于此!分享一张最近的脑图。只有掌握了这些,你才算是SQL编码入门了。触摸你的良心。看这张图,有的就改进,没有的就鼓励。这是我在实战中所学到和体会到的。鉴于本人的技术水平和经验,以及表达能力有限,难免有些地方写得晦涩难懂,有些地方不够深入。希望大家多多反馈,谢谢!
