收获,不止Oracle(第2版)
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.3 体系学习让SQL语句性能提升千倍

2.3.1 一起探索体系学习的意义

“同学们,至此老师已经把体系物理结构基本讲完了,大家回顾一下,能回忆起我讲的内容并全部理解吗?”

“能!”同学们都喊得非常大声。

“确实,梁老师上课如此通俗易懂、生动有趣,让我们理解起来轻松愉快,时间也感觉过得飞快,这真是我听过的最生动的课程了。”小莲心中暗自想到,心情有些激动。

“不过在学习体系结构的课堂里,梁老师认为最重要的内容还没给大家介绍,那就是学习体系结构的意义。

“梁老师上过的课很多,做过的项目更是数不胜数,因此有机会见识不少新人。这些新人少数成长迅速,短时间内就能成为部门甚至公司的技术骨干,而大多数人虽然同样努力却始终进步缓慢,难以独当一面。

“这是为什么呢?

“主要因为不少人为了学习知识而学习,从不曾想过学习这些知识的意义;还有不少讲师为了授课而授课,却很少提及所授内容能为工作带来哪些帮助;最后,新人都能理解大多数知识点,但是由于缺少这些想法和意识,所以一直无法突破提升。

“下面老师给大家举例说明,我为什么要花这么大精力给同学们描述体系结构的课程。

“请大家竖起耳朵听老师说一句话:‘Oracle 的体系结构运行机制不就是那样吗?我们学习了这些原理,又不能改变数据库的机制,它该怎么运行就怎么运行,学习有什么意义?还不如实际一些跳过这个体系结构学习,直接教我们如何建数据库、建用户、迁移数据、写SQL语句等工作中常会遇到的操作,别总弄一些没用的东西。’

“在座的有40位同学,请大家每10人形成一个小组开始针对这句话进行10分钟的探讨,并派代表上来回答。

“另外我还可以说得更简单点,就是让你们去思考知道这些体系知识的你和那些不知道这些知识的人,在操作数据库时会有差异吗?你有什么优势?好好讨论。”

2.3.1.1 同学们不知所学何用

台下讨论得很热烈,10分钟很快过去了,敬昱作为代表首先上场讲述自己小组的观点。

“梁老师,我们讨论的结果是您说的这些没什么用,相比不懂这些知识的人没有优势。”

话音刚落,台下笑成一片,看来梁老师足够随和,同学们也就足够大胆了。

“您说 Oracle 的共享池是为了第一次执行时保存解析过程,避免第二次执行时再做代价高昂的解析。而数据缓存区是为了第一次获取数据时将这些数据从磁盘读到数据缓存区,以便第二次可以避开磁盘查找,直接从数据缓存区找到数据,从而避免物理读。这些东西您描述得那么形象,我们都能理解,可是现实中我们用数据库就是了,关心这些也没意义啊,不理解这些的人和我们不是一样都在操作数据库,不懂这个的人也照样查询数据库,更新数据库,差别就是我们可能细心点,知道相同的语句第二次执行时会更快一点,并且知道原因,仅此而已啊。”

接下来轮到下一组的代表了,扎马尾辫的晶晶走上台来,她和敬昱所在小组持同样的观点,不过这个细心的女孩还提到PGA区的排序,她说道:“梁老师您说排序在PGA内存区中操作,如果尺寸装得下就在内存中完成,否则超出部分会在临时表空间中完成,造成性能低下。我觉得知道这点固然好,但是意义不大,在有特定排序需求的场合下,我们难道就不排序了吗?知道和不知道这些知识点的同学都要写order by 等关键字,没什么差别啊?”

“还有您说的关于日志切换,”晶晶继续说,“LGWR 从日志缓存区中把日志写出,并写进日志文件,写满第1个写第2个……全部写完要循环写的时候,在出现覆盖日志时要把即将被覆盖的日志先转移出去,形成归档文件保存起来,用于数据库的备份与恢复。我觉得我知道这个很开心,不过实际上,不知道这些的人,他只要学会怎么操作这些恢复文件,用于恢复就可以了啊。我现在还只是知道日志可以恢复的原理是什么,却不知道如何恢复,不知道命令是什么,我感觉和不懂这些原理的人差别不大,直接告诉我恢复命令岂不是更实在?”

紧接着林君做代表上来了,这组同学还是持同样的看法,对自己学这些的意义有些茫然。“梁老师,我们很认真地听明白了一致读的原理,您举的转账的例子太生动了,我们不明白都不行了。但是我觉得也没什么实用性,比如我查询很久后返回了一些可能在这期间被频繁更新的数据,我知道其中可能涉及一致读,但是不知道一致读的人也不影响给他返回结果啊,差别就是我们心里比他明白有可能产生了一致读,并且原理是什么,但是在工作中没感觉到有看得见的优势啊?”

小莲有些不好意思地代表第四组上台了,她虽然觉得梁老师上课上得非常生动,但是梁老师非要自己说懂这些体系结构原理和完全不懂体系结构的人在操作数据库上有哪些优势,还真是想不出来。

第四小组讨论后最终是问出了这个问题:“梁老师,共享池的解析是开销很大的操作,我对其中的分析获取最优执行计划印象很深,您说 Oracle 到底是选择索引读还是全表扫描,是由Oracle 自己来决定的,判断代价谁大谁小,代价小的胜出。如此我们何必要关心这个细节,我们又不能左右它们代价的算法,不是听天由命?就此而言,我觉得和不懂这个知识细节的同学没差别啊。”

“批判大会啊,你们让老师觉得自己罪孽深重,需要好好忏悔忏悔了。

“等下老师会去公司财务部一趟,请求财务把我今天的工钱扣回去,而且浪费了大家这么长的时间,应该再恳请公司罚半个月工资,以此表示自己对大家的歉意,你们看这样好不好,可以原谅梁老师了吗?”

梁老师的调侃让台下笑得前俯后仰。

“梁老师的葫芦里肯定要卖什么猛药了!”笑归笑,小莲早已打起十二分精神,准备仔细听梁老师是怎么说的。

2.3.1.2 实际上大有用武之地

“同学们积极参与、善于思考,这是非常棒的,你们是我见过的最认真、最活跃的一批学生。”梁老师首先表扬了一下同学们。

“老师的课本来上得好好的,很快就可以结束今天的课程了,忽然自己没事找事引火烧身,引发你们产生对了解数据库体系结构有无意义的疑问。现在问题抛出来了,老师要是不给你们一个交代就继续上新的课程,估计会被你们赶下讲台。

“那老师来依次回答大家的问题,探讨学习的意义。

“先回答敬昱的提问。我举个例子,假如某数据库是一个很大的数据库,数据量庞大,访问量非常高,而共享池却非常小,那会怎么样?共享池肯定很快就被放满了,缓存的东西要不断地被挤出,结果很多 SQL 语句都难以避免硬解析,因为很快被挤出共享池消失得无影无踪了,于是整个数据库开始运行缓慢。

“同学们,此时我们要做的就是……”

“加大共享池!”

“如果是自动管理模式,就是加大SGA的大小!”

台下回答得很迅速。

“难道这不是了解体系结构的好处吗?”

台下有不少人点头了。

“再比如说,某主机总共才4GB 内存,而运行在其平台上的数据库是一个几乎没有什么访问量的小数据库,可能100MB的共享池就足够了,却被开辟了3GB的SGA内存,500MB的PGA内存。但是由于操作系统内存不足,导致主机运行缓慢,从而导致数据库运行缓慢,我们要做的是……”

“减少SGA的大小!”

“那如果由于数据缓存区过小导致大数据量的数据库产生大量的物理读,怎么办?”

“梁老师,这和共享池情况是类似的,在SGA自动管理的情况下,加大SGA的大小,也等同于加大了数据缓存区的大小,这样数据缓存区够大,装的东西就多,物理读自然就减少了,性能自然就提高了。”敬昱起身回答这个问题。

“敬昱,你们现在还觉得了解体系结构没意义吗?一点都不懂体系结构的人,你觉得他该从哪里入手解决这个问题呢?”

敬昱有些不好意思地笑了笑。

“那我们来看看晶晶的问题,晶晶说的是了解排序在PGA区没有多大意义。如果一个尺寸很大的排序由于内存无法装下要在磁盘中进行,而操作系统却闲置着大量的内存未使用,我们要做的就是……”

“增加PGA的大小,争取容纳下排序的尺寸,从而避免物理排序。”晶晶听到梁老师故意放慢语气后,起身接下了梁老师的话。

“那如果主机的内存不足,而某特定数据库几乎没有什么排序的应用,我们就可以……”梁老师又放慢了语调。

“减小PGA,腾出占用的内存分配给操作系统使用。”还是晶晶回答了。

“假如一个数据库系统存在大量的更新操作,产生了大量的日志需要从Redo Buffer中写出到日志文件,结果梁老师说过的那种日志写满然后切换到下一个日志的频率不断加快。这里大家要注意一点,切换过程中数据库需要等待切换完成才可以正常运作,因为切换没完成,LGWR就无法把Redo Buffer中的数据继续写出来,而数据库中Redo Buffer产生的记录总是先于数据缓存区产生的,这是串行的顺序,那此时数据库更新的动作就根本不可能成功,一定要等待日志切换成功,世界才恢复正常秩序。

“那现在日志频繁地切换,我们的更新一直在停停走走,我们要做的事是……”

整整过了30秒,晶晶终于明白过来了:“梁老师,日志组的这些日志越大,就越经得住写,切换就越少,等待时间就越短,所以加大这些日志文件的尺寸,是这样吗?”

“晶晶,你还觉得了解体系结构没优势吗?不懂体系结构,你能这样考虑问题入手优化系统吗?”

晶晶也不好意思地笑了笑。

“接下来是林君的问题,他们组提到查询的一致性问题,认为这个细节无须掌握,那你们仔细回想一下,什么时候这个查询会出错?”

“当前镜像无法找回原来的记录,被覆盖重写时就会报错退出,好像错误号是ORA-01555,Oracle宁愿查询失败也不愿意查询出错误不一致的结果。”林君回答得很流利。

“记得很清楚嘛,看来林君对梁老师账户凭空多出500元没请客而耿耿于怀啊。”

又是一阵大笑。

“现在某应用系统因为查询老出ORA-01555错误返回不了结果给下一个模块使用,导致生产出现故障了,你们来帮他们出出主意吧,我们能出的建议是……”

“检查这个语句为什么执行这么慢,让这个语句执行得快一点,就不容易被更新直至覆盖重写啊。”林君稍作思考就回答了。

“对啊,这不是回答得非常好吗?优化也许是加一个索引,也许是清理表的历史数据,让表的记录小一些。但是不管用什么方法,语句执行快了,这个失败的概率就大大降低了,仔细想想梁老师之前的上课内容,还有没有其他方法也可以解决这个查询失败问题?”

“梁老师,增大undo_retention的取值,比如写一个很大的时间,让回滚段在这段时间内都不允许被覆盖重写。”小莲起身回答了。

“好了,现在林君这个小组的同学还认为学习体系结构没意义吗?”

现在不只是林君不好意思地笑了笑,所有同学都觉得有些难为情了。

“不过这里要注意一点,undo_retention只是参考保留时间并非强制,除非另外设置undo表空间的Retention Guarantee属性,使之强制保留。此外也可考虑增加undo表空间的大小。现在轮到最后一组同学的问题了,小莲提出来的是Oracle共享池在解析过程中,选择全表扫还是索引读是我们无法左右的,所以知道这个也没意义。确实,有时索引高效有时全表扫描高效,这和返回的记录数的多少很有关系。返回绝大部分的数据,一般情况下倾向于全表扫,返回少量的数据,一般情况下倾向于索引读。

“我现在想问的是,你如果没建索引,会有索引扫描吗?”

“当然不会!”小莲不假思索地回答。

“那还没意义吗,了解体系结构的人知道优化器能解析出代价最低的执行计划,那你就别让优化器巧妇难为无米之炊,可以多送点武器供它比较选择,看看哪个兵器好用啊,不懂体系结构的人可以想到这一层吗?当然,索引本身也是一个非常重要的知识,后续我还有机会给大家做系列培训,到时候我会花很多时间给大家详细描述索引。”

“哎呀,丢人了,我问的问题怎么这么傻啊?”小莲忽然有一种从梦中惊醒过来的感觉,顿时脸红到耳根。

“我们怎么都不会往梁老师说的这些方面去想问题呢?”台下有些寂静,大家都不约而同地想到了这个问题。

2.3.2 单车到飞船的经典之旅

“刚才老师回答了不少同学的疑问,说明了学习体系结构是很有意义的。看来只要善于思考,善于联系,我们就能很容易地应用所学的知识解决遇到的问题。

“现在我给大家讲一个具体的案例,通过分析一系列等价 SQL 语句的性能差异,来分析其中的原因所在。”

2.3.2.1 未优化前,单车速度

“首先构造环境,保证下列语句执行过了,t表已经存在,见脚本2-29:

脚本2-29 单车到飞船试验前的准备工作

“有一个开发人员写了类似如下的一个简单存储过程,实现了将1到10万的值插入t表的需求,具体如脚本2-30所示:

脚本2-30 单车到飞船试验前构造proc1

“该语句从需求实现上没有任何问题,我们执行脚本2-31:

脚本2-31 首次试验42秒完成,仅是单车速度

“该语句用42秒时间完成10万条记录的插入,大家觉得速度快吗?”

“1秒插入2000多条记录,速度好快啊!”小莲在数学上的反应还是很敏捷的。

“哦,你还希望能更快一点吗?”梁老师问。

“哦,当然希望了,肯定是越快越好了。”小莲回答得不假思索。

“其实这个简单的过程如果想更快,靠的就是对体系结构的理解,下面大家跟我查询一下该过程执行中,数据库共享池中的相关情况。

“共享池中缓存下来的SQL语句以及hash出来的唯一值,都可以在v$sql中对应的sql_text和sql_id字段中查询到,而解析的次数和执行的次数分别可以从PARSE_CALLS和EXECUTIONS字段中获取。

“由于这个过程proc1执行的是insert into t 的系列插入,于是我们执行如下语句来查询proc1在数据库共享池中执行的情况,具体如脚本2-32所示:

脚本2-32 原来是因为未用绑定变量

“为了让SQL语句及展现结果看起来更美观,我将上述SQL语句在PL/SQL Developer工具中查询(这个工具有着很友好的界面,尤其适合数据库开发人员使用,因此除了介绍先前的sqlplus 工具外,也顺道提一下这个PL/SQL Developer工具),发现共享池中有大量的类似的SQL语句,而sql_id各自不同,每条语句都只解析1次,执行1次,解析了10万次,怪不得速度如此之慢,如图2-26所示。

图2-26 绑定变量

2.3.2.2 绑定变量,摩托速度

“此时我们这么想,要是insert into t values(99898)、insert into t values(99762)等这10万条语句能合并成一种写法,比如用变量代替具体值,成为insert into t values(:x),那岂不是这10万条语句可以被hash成一个sql_id值,不就可以做到解析1次,执行10万次了吗?这样可以大大减少解析时间。

“这就是数据库的一个典型优化,绑定变量优化!

“接下来我们将proc1改进为proc2,具体写法如脚本2-33所示:

脚本2-33 第2次改进,将proc1改造成有绑定变量的proc2

“接下来我们继续测试proc2过程(注意,重建表的目的是为了公平,测试都在无记录的空表上进行,并且共享池都清空),如脚本2-34所示:

脚本2-34 第2次改进后8秒完成,单车变摩托车

“这次我们惊奇地发现,速度从原来的42.87秒缩减为8.41秒,大幅提升了,每秒插入记录数达到10 000多条,大大超过之前的每秒插入2000多条的速度,为什么会这么神奇呢?”梁老师停下来问大家。

“因为语句被绑定变量了,解析次数变少了!”梁老师的话同学们记得很牢。

“很好,那我们一起看看吧,看看有什么变化,如图2-27所示。

图2-27 解析与执行次数

“虽然插入的语句值各不相同,但是都被绑定为:x,所以被hash成唯一一个hash值,名称为dxz576128adaw,很明显可以看出解析1次,执行10万次,这就是速度大幅度提升的原因了。

“这下大家对这个速度满意了吧?”

小莲这下才发现,原来简单的体系结构后面还真有不少玄机呢,也不只是课上梁老师说的加大减少共享池这么简单,小莲觉得今天的课太值了。

2.3.2.3 静态改写,汽车速度

“大家还想不想再快一点?”梁老师这次开口吓了大家一跳。

“梁老师,您太贪心了吧!”晶晶打趣地说道,看来课堂上同学们还真是被梁老师带动得无拘无束了,什么话都敢说啊。

“其实真的还能再快一些的,你们看看这两个过程,是否觉得哪里写得有点别扭?”梁老师提醒大家认真看proc1和proc2。

“梁老师,这个execute immediate和双引号是什么意思啊,为什么不直接写成insert into t values(i)啊?”刚才开玩笑的曾祥也提问了。

“不错!终于看出来了,execute immediate是一种动态SQL的写法,常用于表名和字段名是变量、入参的情况,由于表名都不知道,当然不能直接写 SQL 语句了,所以要靠动态 SQL语句根据传入的表名参数来拼成一条SQL语句,由execute immediate调用执行。但是这里显然不需要多此一举,因为insert into t values(i)完全可以满足需求,表名就是t啊。

“我们来将其改写成proc3,如脚本2-35所示:

脚本2-35 第3次改进,将proc2改造成静态SQL的proc3

“接下来我们继续测试proc3的性能,也是在公平的环境下操作的,如脚本2-36所示:

脚本2-36 第3次改进后6秒完成,摩托变汽车

“大家看看,现在是什么情况?” 梁老师笑着说。

“哇,又快了!”晶晶惊叫起来,引来了一片笑声。

“为什么会快了,我们分析一下,这条语句肯定用到了绑定变量,一般来说,静态 SQL 会自动使用绑定变量,我们来查看一下,如图2-28所示。

图2-28 静态SQL解析与执行次数

“果然如此,proc3也实现了绑定变量,而且动态SQL的特点是执行过程中再解析,而静态SQL的特点是编译的过程就解析好了。这点差别就是速度再度提升的原因。现在大家对这个速度满意了吧?”

台下纷纷点头。

2.3.2.4 批量提交,动车速度

“还能再快一点吗?”梁老师再次发问引发台下一阵大笑,因为大家这时都认为老师是在开玩笑。

“别笑,我可不是开玩笑,同学们再执行这个proc3,看看有什么新发现。”

“梁老师,我看到commit了,我觉得应该放在循环的外面而不是里面。放在里面意味着每插入1条,就要提交1次,放在循环里就要提交10万次,而放在循环外就是全部插入完后提交1次,我觉得少提交更好。”细心的小莲发现了commit 位置的不同。

“说得非常好,commit触发LGWR将Redo Buffer写出到Redo Log中,并且将回滚段的活动事务标记为不活动,同时在回滚段中记录对应前镜像记录的所在位置,并标记为可以重写,切记commit可不是写数据的动作哦,写数据将数据从Data Buffer刷出磁盘是由CKPT决定的,大家应该对这个有印象。

“所以commit做的事情开销并不大,单次提交可能需要0.001秒即可完成。另外不管多大批量操作后的提交,仅针对commit而言,也是做这三件事,所花费的总时间不可能超过1秒。打个比方,100万条更新批量执行后完成commit的提交可能也就需要0.8秒,但是100万×0.001的时间可是远大于1×0.8的时间。

“下面我们来做做试验,将proc3改写为proc4,具体如脚本2-37所示:

脚本2-37 第4次改进,将proc3改造成提交在循环外的proc4

“接下来我们继续测试proc4的性能,也是在公平的环境下操作的,如脚本2-38所示:

脚本2-38 第4次改进后2秒完成,汽车变动车

“速度是多少?”梁老师回头看着大家。

“哇,2秒就完成了!”还是晶晶的惊叫声。

“等同于每秒50 000条记录,原先可是每秒2000多条啊,不可思议!”小莲数学换算总是最快。

2.3.2.5 集合写法,飞机速度

“还能更快吗?”梁老师没完没了啊。

“不可能!”这下同学肆无忌惮地大笑了,他们知道梁老师这回肯定是故意的了。

“不可能?看来你们又认为老师在开玩笑了,如果老师能让插入该表的动作更快,你们请老师吃饭,否则老师请你们吃饭?”

“没问题!”同学们应答得好干脆,他们其实心里也知道,这请客的说法一定是开玩笑,课堂的气氛被调到了最高潮。

“好吧,同学们,大家看这条SQL语句的写法,如下:

“表示我将1到10万记录依次插入到t表中,完全满足刚才的需求,不过这种写法大家可能略感陌生,结果却是对的。现在我们执行脚本2-39:

脚本2-39 第5次用集合写法后0.25秒完成,动车变飞机

“大家认真看看完成的时间吧。”梁老师得意地回过头望着大家。

“0.25秒!”这次不再是晶晶一人的声音了,是全体同学一起喊起来了。

“每秒插入40万条,太快了吧!”小莲再次喊出声来。

“为什么会快这么多呢?其实是因为原先的一条一条插入的语句变成了一个集合的概念,变成了整批地写进Data Buffer区里,好比你要运砖头到目的地,一种运送方式是先将一块砖头拿到目的地,再返回拿第二块,直到拿完全部。而另一种运送方式是将砖头全部放在板车上一起推至目的地,只是这里的目的地是Data Buffer区而已。

“听明白了吗?”

“听明白了!”大家都很激动,梁老师真像一个魔术师。

“听明白就好,现在你们该好好想想晚上请老师去哪里吃饭了。”

同学们都乐了,大家心里都知道梁老师是在开玩笑。

2.3.2.6 直接路径,火箭速度

“没声音啊,看来大家怕花钱啊,要不老师再给同学们一个机会,如果我还能让这个插入语句更快,大家就请客,否则老师请客,如何?”

梁老师有完没完啊,都每秒40万条的速度了,还想快,疯了吧。同学们议论纷纷。

“那我开始了,因为前面的完成时间都已经到零点几秒了,太小会有误差,所以我准备把数据量放大100倍,10万条改为插入1000万条,前面飞机速度的语句变成如脚本2-40所示:

脚本2-40 试验准备,将集合写法的试验数据量放大100倍

“插入1000万条记录完成的时间是23秒多,大致为每秒43万条记录,和插入10万条记录时的速度大体接近。下面我改用create table 的直接路径方式来新建t表,看看这样的方法能否提升速度,见脚本2-41:

脚本2-41 第6次改进,直接路径让飞机变火箭

“测试结果是,速度又有了2倍多的提升,只需要10秒即可完成,等同于插入速度为每秒100万条,要不是亲眼所见,还真不敢相信吧。

“同学们知道这是为什么吗?真正的原因在于,insert into t select ……的方式是将数据先写到Data Buffer中,然后再刷到磁盘中。而create table t 的方式却是跳过了数据缓存区,直接将数据写进磁盘,这种方式又称为直接路径读写方式,因为原本是数据先到内存,再到磁盘,更改为数据直接到磁盘,少了一个步骤,因而速度提升了许多。

“直接路径读写方式的缺点在于由于数据不经过数据缓存区,所以在数据缓存区中一定读不到这些数据,因此一定会有物理读。但是在很多时候,尤其是海量数据需要迁移插入时,快速插入才是真正的第一目的,该表一般记录量巨大,Data Buffer甚至还装不下其十分之一、百分之一,这些数据共享的意义也不大,这时,我们一般会选择用直接路径读写的方式来完成海量数据的插入。

“同学们,听明白了没有,现在大家甘心请客了吧?”梁老师时刻不忘调侃。

台下同学都听呆住了,梁老师这堂课真是神了,大家半天没回过神来。

2.3.2.7 并行设置,飞船速度

“大家这次请客是请定了,具体时间老师通知哦。”

台下哈哈大笑,大家还是回过神来了,今天这堂课被梁老师弄得一愣一愣的。

“同学们,插入语句还能再快吗?”

这下台下同学们都不敢应答了,梁老师没完没了,却每次都能不断加速,而且用到的知识又和体系知识息息相关,让自己一听就明白了。可以看出梁老师这个经典案例是精心构造的,真可以说是经典中的经典。

“看来是被我给忽悠住了,大家都不敢应答了。”梁老师笑着说道,“其实遇到性能好的机器,还是可以大幅度提升性能的。大家看如下语句,我设置日志关闭nologging,并且设置parallel 16 表示用到机器的16个CPU,结果在笔记本环境下收效不是很明显,因为我的环境是单核的机器。

“后来我把如下SQL语句运行在强劲的服务器上,有16个CPU,下面的语句仅仅在4秒不到的时间内就完成了,速度相对于前面的火箭速度而言,快多了,几乎是每秒300万条的插入速度,具体如脚本2-42所示:

脚本2-42 第7次改进,并行原理让火箭变飞船

“不过并行最大的缺点就是占用了大多数CPU的资源,如果是一个并发环境,很多应用在运行,因为这个影响了其他应用,导致其他应用资源不足,将引发很多严重问题,所以需要三思而后行,了解清楚该机器是否允许你这样占用大部分资源。

“好了,今天我以一条最简单的插入顺序数字进某表的 SQL 语句为例,方法从存储过程实现到仅用单条SQL语句完成,速度从原先的每秒2000多条提升到每秒300万条,这中间都做了哪些改进呢,是否都和体系结构有关呢?

“希望大家好好复习这一节的经典案例,回忆一下速度的6次飞跃之旅,好好感受一下灵活应用知识的无限魅力。”

2.3.3 精彩的总结与课程展望

“今天的课程即将结束,大家用心地思考15分钟,想想今天一天都收获了什么,学到了什么,老师会提一些问题让大家回答,希望各位能积极参与、无拘无束、畅所欲言。”

时间确实过得太快了,从早上到现在仅课堂时间就已经7个半小时了,大家居然丝毫感受不到上了一整天课的疲倦,都为沉浸在精彩纷呈、跌宕起伏的课程中而兴奋不已。小莲闭上眼睛,开始从头到尾回忆并思考今天的上课内容,其他同学也有和小莲一样闭目思考的;也有三五成群相互讨论的;也有独自翻阅自己记录的笔记的;还有打开电脑学习梁老师提供的PPT教材的……

“老师今天上了什么内容?”

“体系结构,说得很详细,还有不少生动的例子。”敬昱喊声最大,其他声音的内容也大致如此。

“那最大的收获有哪些呢?”梁老师继续提出第2个问题。

“明白了体系物理结构的原理。”

“知道了学习体系结构的意义。”

“听到了很多案例,以后可以借鉴。”

台下七嘴八舌……

2.3.3.1 最大的收获应该是思想

“同学们,虽然你们回答得还不错,但是梁老师并不是很满意,你们知道原因吗?”说到这里梁老师停顿下来看着大家。

台下顿时安静下来,等着梁老师继续往下说。

“首先,最遗憾的是,我在问今天上什么内容时,没听到有人说我早上总结的学习方法、学习路线这部分内容,而这部分内容,我觉得重要程度要超过接下来的体系结构的描述。

“我谈手机,是要让大家知道学习首先需要学会分类总结。

“我描述角色和具体知识点,是让大家知道学习首先要学会把握先后顺序,抓住重点。

“我说的知识获取的途径,是让大家知道自学其实是非常重要的。虽然梁老师后续还会继续给大家上系列课程……”

“啪啪啪”台下又突然响起了掌声,打断了梁老师的话。

梁老师一愣,笑笑继续往下说,“但是梁老师永远不会教你们建表建索引以及写具体 SQL语句的语法和命令,这需要你们自己去学习,否则这就不是工作技能培训,而是大学甚至中学的课堂学习了。我只会教大家最重点的知识、思想及案例,绝不是所有的知识点,语法更不会在上课的范畴内,所以我给大家介绍了具体获取知识的途径,其中官方文档的CONCEPT务必仔细阅读一遍,内容不多,但是说明了概念,为具体的知识细节提供了详细的链接。

“那还需要老师来上课吗?当然需要,因为我们要快速进步,而不是缓慢前进。官方文档虽然全面、正确,但是永远不会教我们什么时候选择什么技术,什么时候不能选择什么技术;也不会教我们如何将系列技术巧妙结合;不会和我们分享经典的案例;更不会教我们解决问题的思想和方法。而这些才是最重要的,就是梁老师要教给大家的,但是前提是必须先把官方文档的CONCEPT熟读完毕,能很快查阅到某些技术的具体语法及步骤,比如建表建索引、如何写一个查询语句。记住,梁老师不会教这些可以简单搜索到的内容,没有必要也没有时间,这方面要靠自己,方法已经告诉你们了。”

说到这里,梁老师停下来,对大家说,“老师是不是有点遗憾啊?”

同学们都不好意思地笑了笑,小莲也觉得感触颇深,梁老师可谓用心良苦,其中那个描述什么角色学哪些知识点的Excel图估计也做得煞费苦心,自己怎么就没好好体会呢。

“老师还有遗憾,你们最大的收获提及明白了体系结构的原理,这没错,将来会对数据库相关工作带来很大的好处。还有同学说知道了了解体系结构的意义,也挺好的。不过如果有人说借鉴到了Oracle设计的思想,我将更满意。

“这里的共享池和数据缓存区显然是遵循了一个在少做事甚至不做事的情况下,完成相同的工作任务的原理,这不是一个非常完美的优化思想吗?在后续课程中,如何优化是重点内容,大家会体会到我反复提及这个少做事不做事的朴素的优化思想。同学们还记得骑单车到乘飞船的难忘之旅吧,仔细回想一下这是不是少做事不做事的经典案例呢?只是听明白体系结构原理而没有深入思考下去的人,他的单车永远无法变成飞船。”

2.3.3.2 老师的课程展望与规划

“下面我们进行一下未来课程的展望吧,未来大家如何学习,梁老师会继续给大家讲什么?大家觉得要不要规划一下?”

“要!”

“首先请大家自行从 Oracle 官方网站下载 CONCEPT 文档,并尽量在一周的时间内阅读完毕(可先不阅读其中指向的细节部分,那是自己选择性阅读的内容)。此外可以阅读Oracle 11g也可以阅读Oracle 10g版本,这个请大家务必做到,我这里有Oracle 10g的官方文档CONCEPT的中英文对照文档,大家如果为了加快阅读速度,可以参考一下中文说明,不过大家要记得英文阅读能力始终是工作中最重要的能力之一。

“那我接下来会给大家讲什么内容呢?请大家再次阅读角色分析图2-29。

“我的教学方法是有些特别的,绝不是为了讲述某个知识而讲述某知识,那样不仅效果不明显也无趣,我想教的内容是一个整体性的内容,是有启发性的内容,好比今天的课堂,大家应该已经感受到了。

“基本原理这块还是接下来上课的重点,体系物理结构已经描述完毕了,剩下的就是体系逻辑结构、表及索引等的描述。接下来我将描述开发技能、管理知识以及优化原理,同时对设计相关知识也会做一些描述。

图2-29 角色分析探讨

“哇,这么多课程该如何上啊,梁老师是不是太贪心了?”梁老师打趣地停了下来。

同学们会心地笑了一下,难忘的一天课程下来,他们早已被梁老师的用心和激情深深打动了,对梁老师很是尊重和钦佩。

“其实我不是来给大家上数据库内容的,主要是来谈理想,谈人生的。”

小莲不自主地点了点头表示赞许。

“关于课程的内容,五大领域都有涉及但是重心不一样,基本原理将会占很大的篇幅,因为这是理解后面知识的基石。

“我在这里郑重宣布:优化知识和优化思想将成为全部课程的中心内容,并结合各种案例融入各领域中去,如基本原理与优化、开发与优化、管理与优化、设计与优化。然后,然后还有优化的课程吗?”

“没了!”少数同学附和地应答了。

“是没了,但是从头到尾优化的思想都贯穿其中,不只是具体的优化知识,更重要的是思想。我用心将后续的课程打造成一个充满世界观、方法论及精彩案例的心灵之旅,让大家能成为旅人而非学生。

“基本原理中体系结构的学习大家都体验过了,后续老师将会延续这种风格和大家共度心灵之旅。虽然这种心灵之旅不是阅读官方文档所能达到的,但是梁老师的课程和官方文档却是需要互相补充、结合完善的。希望老师在精心准备课程的时间里,大家能抽空认真地选择性地阅读官方文档。今天的课程到此结束,期待我们的下次再会!”

台下响起了热烈而又长久的掌声。