前几天一个开发的同事来找我咨询一个问题,说是咨询,其实是开发的同事也不是非常清楚里面的逻辑,因为历史系统,历史原因,各种原因吧,所以我也是带着试试看的态度来帮助了这位同事。
这位同事知道这个咨询我的是一个存储过程。基本思路是从千万级的表table1中查出结果集,然后在table2,table3,table4都插入数据。
这个存储过程是怎么触发的呢,从开发同事那里得到的信息是在大概每周三凌晨运行一次,但是具体怎么触发的他们就无从得知了。要确认这个信息也花了一点时间。首先排除crontab,然后在scheduler中开始查找。
因为scheduler不像pl/sql还可以直接从dba_source里面可以模糊匹配出来需要的信息。所以这个时候借助了dba_scheduler_jobs这个数据字典,直接找到近半个月的执行情况。
select owner,job_name,last_start_date,end_date,NEXT_RUN_DATE from dba_scheduler_jobs where last_start_date between to_timestamp('2015-12-01 05:00:00','yyyy-mm-dd hh24:mi:ss') and to_timestamp('2015-12-10 08:00:00','yyyy-mm-dd hh24:mi:ss') and owner='XXXX' order by LAST_START_DATE;
通过这个语句得到了一个粗略的job执行列表,如果想查看更多的明细可以使用,比如job为test_vip_v3,则可以通过下面的方式来得到job的定义语句。
select dbms_metadata.get_ddl('PROCOBJ', 'TEST_VIP_V3',SCHEMA=>'XXXX') from dual;
其实也是花了一些功夫,总算定位到了,其实最后回过头来看,其实通过dba_scheduler_jobs中的另外几个字段也能够定位到。
得到的执行频率定义为 'FREQ=WEEKLY;BYDAY=WED;BYHOUR=1;BYMINUTE=3;BYSECOND=25' 这个信息和开发同学的描述是一致的,而且经过确认确实是。
好了,问题基本清楚了,他们开始尝试提出一些想法,其实也算是需求吧。
目前的业务实现,在每次dml操作table 2之后,还是需要对比修改前和修改后的数据变化,把一部分过滤后的数据插入到一个新的日志表中。
按照这种情况那就是需要在每次操作前都需要把表table2的数据做一个逻辑备份或者逻辑复制了。所以这个工作比较简单,就是创建一套同样的表结构,然后每次操作前做一个基本的备份即可。
后面的操作就如下所示了。其实按照之前描述的,其实就是需要创建一个表table5,table6,而两者做minus运算的部分,因为他们目前还评估不了,所以我就建议他们这个步骤先设置为手动,如果两个表数据量太大,但是minus运算结果集不大,可以考虑在备库做这类查询,把结果集缓存出来,从备库反推到主库。
如果数据量不大,那么就可以直接考虑在主库做这类操作。所以这个步骤考虑到手工触发,我就建议他们提供一个存储过程来代替,再手工也不能纯手工操作。到时候开发同事或者DBA都可以代劳。
所以这个简单的需求,最后就可以分解出下面几件需要做的事情
1.开发同学提供table 5,table 6的ddl语句
2.开发同事提供两个表minus运算的语句和条件,DBA来查看是否有更多的优化空间
3.根据优化建议,可以建议补充哪些相关的索引,一起确认哪些索引在table5,table6中是否需要,是否需要再添加。
4.开发同学提供minus的细节,把这个包装成独立的存储过程
5.table5在每次更新前需要truncate,然后重新初始化,开发同学提供初始化逻辑。
6.DBA对现有流程进行性能评估,查看是否有改进的空间。
大体聊了十多分钟,然后就达成了上面的共识,然后就是分阶段来完成了。
今天已经周三了,从目前的情况来看,
table5数据量在千万,但是minus的过滤结果集不大,所以这个操作就放到主库执行即可,
minus数据merge进入table 6的过程耗时在2分钟,已经达到了预期目标。所以可以考虑把这个存储过程直接揉入原有的存储过程中,就不用单独在定义一个job来触发了。
没有其它业务受到影响
所以这么一个简单的业务需求就基本划上了句号。听开发同事反馈,以前有的时候job会执行几个小时,那么这种活就是优化的部分了,我还是比较喜欢这种提升空间大的活。距离下次周三还有几天,还有很大的空间可以改善。
可以看到一个本来开发也不熟悉的流程经过我们的讨论和确认逐渐清晰起来,也确实解决了不少的潜在问题,毕竟我们只是做一个方案的执行者,我们也可以引导他们。给他们适当的建议。