技术人生——第12集:思想为王,功能在后
梁敬彬梁敬弘兄弟出品
往期回顾
技术人生——第1 集: 机械出身,我不机械
技术人生——第2 集: 膨胀自信,午夜惊魂
技术人生——第3 集: 穿越救赎,因祸得福
技术人生——第4 集: 便捷惨案,泣血蜕变
技术人生——第5 集: 剑破冰山,畅行无阻
技术人生——第6 集: 收获惊喜, 不止O记
技术人生——第7 集: 一本书籍,一所小学
技术人生——第8 集: 打破枷锁,火箭跃升
技术人生——第9 集: 拓荒立制,创研究院
技术人生——第10集:幸运敲门,新曲线成
技术人生——第11集: 收获不止,SQL优化
1. 知易行难,大道至简
小方那句“大师,再来一本吧!”,像一颗投入平静湖面的巨石,在庆功宴的餐桌上,激起了千层浪。同事们纷纷放下酒杯,开始热烈地讨论、并附议这个“疯狂”的提议。
那一晚,我是在一种混杂着酒精、兴奋和巨大压力下回到家的。
关上门,夜深人静,白天的喧嚣散去,小方的提议和同事们期待的眼神,却在我脑海里反复回响。我铺开一张白纸,试图为这本“众望所归”的新书,搭建一个框架。但我的脑中,却和这张白纸一样,一片空白。
我发现,在酒桌上高谈阔论,和真正坐下来体系化地输出一本专著,完全是两码事。要把“性能之道”这种形而上的“思想”,用文字清晰地表达出来,实在是太难了。知易行难,那一刻我体会得淋漓尽致。
之前积累的成功经验,此刻反而成了我最大的枷锁。我怕写不好,会辜负所有人的期待;我怕写不出来,会搞砸自己“畅销书作者”的名声。一种前所未有的创作压力,让我再次有了“打退堂鼓”的念头。
又是一个周末,我又一次,带着我的困境,找到了我的弟弟。我把我的担忧告诉他:“所有人都觉得我行,但我自己知道,我可能……真的不行。境界这东西,虚无缥缈,我怕我写砸了。”
弟弟听完,笑了:“哥,你忘了你的价值是什么吗?小方他们为什么会提出这个建议?因为他们想听的,不是你讲‘大道理’,而是想看你当年是怎么不拘一格解决问题的。你不需要过于纠结思想的定义,你只需要去再现那些诞生了这些思想的真实场景!把你的那些故事写下来,道理,不就在其中了吗?”
他一语惊醒梦中人!我需要的,不是凭空创造,而是忠实地“再现”!我的思路,豁然开朗,过往的回忆在脑海中浮现出来。
2. 空间换时间的“作弊”
第一个故事,充满了“投机取巧”的“作弊”色彩,那是在职业生涯早期,我还没有从研发转成DBA。当时,老板每天雷打不动地,要在午饭前看到一份业务统计报表。这个报表逻辑极其复杂,每次查询,都要跑上三四个小时。于是,每天的办公室,都会上演同样的剧情:上午九点,运维紧张地手动触发脚本;然后,从老板到业务部门,再到我们技术部门,所有人都在焦急地等待。老板时不时会从办公室探出头来问一句:“小伙子,报表好没好?”那种压力,现在回想起来都觉得窒息。
在尝试了各种SQL调优都收效甚微后,我开始反向思考:老板要的是“昨天”的数据,这是一个“历史确定”的结果。既然如此,我为什么一定要在他需要的时候,才开始计算呢?
于是,我用了一个当时看来近乎“作弊”的手段:我写了一个简单的数据库作业(Job),让它在每天凌晨两点,系统最空闲的时候,就悄悄地执行那个复杂的查询。
-- 凌晨2点定时执行的SQL(伪代码)
CREATE TABLE report_result_daily AS
SELECT biz_type,SUM(amount) AS total_amount,COUNT(*) AS total_count
FROM massive_biz_table
WHERE create_time >= TRUNC(SYSDATE) - 1 AND create_time < TRUNC(SYSDATE)
GROUP BY biz_type;
然后,我改造了报表程序,让它不再执行那个长达三小时的复杂查询,而是直接从我新建的这张小小的“结果表”里取数。
-- 白天老板查询的SQL,0.5秒出结果
SELECT * FROM report_result_daily;
第二天上午,当老板再次要报表时,我当着他的面,轻轻点了一下鼠标,报表瞬间就弹了出来。他当时震惊的表情,我至今记忆犹新。
我利用对业务场景的理解,用“空间”换“时间”,“手动”解决了这个难题。果不其然,许多年后,Oracle官方正式推出了这个功能,并为我当年这个“作弊”的方法,取了一个非常学术的名字——“物化视图”(Materialized View)。
3. 众人拾材火焰高
第二个故事发生在我刚转DBA不久,那是一个大型数据迁移项目,其中核心的存储过程成了瓶颈,跑一次要十几个小时,严重拖延了整个项目的进度。当时,大家都聚焦在“如何优化这个存储过程本身”,把那几百行代码翻来覆去地研究,但效果甚微。
我被叫到“作战室”时,看到的是一屋子愁眉不展的同事。我没有去看代码,而是打开了数据库服务器的性能监控。我发现,在执行这个存储过程时,服务器16个CPU核心,只有一个是“一柱擎天”,另外15个都在“围观”。
我立刻就有了一个大胆的想法:我们为什么一定要在一个进程里,把这件事做完呢?
我把目光从数据库内部,移到了数据库的外部——应用层。我快速地用Shell写了一个简单的调度脚本。
Bash
#!/bin/bash# 调度脚本核心逻辑(伪代码)
TOTAL_KEYS=$(get_all_keys_from_source_table)
KEY_CHUNKS=($(echo $TOTAL_KEYS | xargs -n 10000)) # 每10000个key作为一批for chunk in "${KEY_CHUNKS[@]}"; do# 将每一批key作为参数,后台启动一个独立的数据库处理进程run_oracle_procedure "$chunk" &
done
wait # 等待所有后台进程执行完毕
这个脚本的核心,就是将上亿条数据,均分成几十份,然后,同时开启多进程,让每个进程都去处理那一小份数据,性能提升的原理很简单,从单个进程干活变成多个进程干活,众人拾材火焰高。
结果是惊人的。原来需要12个小时的工作,现在只用了一个多小时就完成了。正如你可能猜到的那样,多年以后,数据库厂商们也想通了这一点,纷纷推出了“并行查询(Parallel Query)”功能,其核心思想,与我当初那个“野路子”,竟如出一辙。
4. 错峰出行有规划
第三个故事,关于“资源竞争”。
当时的系统,一到半夜,CPU就全线飙红,各种任务互相“打架”,告警邮件像雪片一样飞来。因为财务的月度报表、业务的批量跑批、数据的备份任务,全都约定俗成地,挤在了凌晨这个“黄金时间”执行。
我的解决方案,简单到近乎“朴素”:我没有去优化任何一个任务,而是做了一张“任务时刻表”,拉着各个业务部门负责人,让他们“错峰出行”——财务报表提前到晚上10点;数据备份推迟到凌晨4点;核心业务跑批,则牢牢占据凌晨1点到3点这个最核心的时间窗口。
仅仅是通过这种“手动资源调度”,系统的“午夜拥堵”就迎刃而解。是的,你又猜对了,数据库厂商们,也为这种“错峰填谷”的思想,推出了一个官方的功能,叫做“资源管理器”(Resource Manager)。
想到这三个故事,我长舒一口气。我更加坚信,优化的尽头,是思想。真正的专家,不是一个精通所有工具的“工匠”,而是一个能洞察问题本质,并为之创造工具的“思想家”…
未完待续…
系列回顾
“大白话人工智能” 系列
“数据库拍案惊奇” 系列
“世事洞明皆学问” 系列