蝼蚁之穴,悔已千堤

来源:互联网 发布:手机如何注册知乎 编辑:程序博客网 时间:2024/04/27 19:15

先是毁,再是悔,确切的说,是千堤已毁,悔矣!

环境 oracle10.2.0.4 + IBMP570(8C 32G)

索引的问题弄死了上面的配置。

前天,一系统反应慢,约半天时间,宕机。查看weblogic日志,里面提示<Oct 24, 2011 3:43:08 PM CDT> <Error> <WebLogicServer> <BEA-000337> <ExecuteThread: '3' for queue: 'weblogic.kernel.Default' has been busy for "1,737" seconds working on the request "Http Request: /****************************.jsp", which is more than the configured time (StuckThreadMaxTime) of "600" seconds.> ,都是延迟响应。查看数据库资源。disk busying 近乎100%,过会,diskbusy下降,转化为CPU wait,然后,wait下降,转换为CPU USER使用,导致CPU被100%占用,业务系统奇慢。

disk 为100%,肯定不正常,最先考虑的是磁盘有问题或盘柜有问题,原来曾经出现过这现象,是盘柜有一路控制器offline,随后,为了保证数据不丢失,关闭了写缓存。

查看磁盘,正常状态,连上盘柜(192.168.128(9).101(2)),除了一个没在最佳路径的错误,没有其他异常。一天的折腾,无果,问题点转向上层。

通过topas查看单进程CPU长期超过10%的进程号,关联查对应的sql,执行计划正常,直接执行,响应速度正常,结果正常。晕了。

这时,有个同事,发过来个执行很慢的sql,这个sql我曾经执行过,没问题,此次不过是换了变量。执行,到1000条时没反应了,等待5分钟后,又出来2000条记录,又大约5分钟,出来剩下的2000多条记录。

select a.cellid,
       a.sheetname,
       a.tempcol || a.temprow position,
       nvl2(a.formula_exp,
            ysf_dynamicgetvalue(a.formula_exp, 2012, 0),
            b.tvalue),
       b.modify_status,
       decode(c.flag, null, 35, 99, 35, c.flag) FLAG,
       decode(a.formula_exp, null, 0, 1) isFormula
  from (select budget_value tvalue,
               cellid,
               decode(modify_status, null, 1, 0, 1, 16711935) MODIFY_STATUS
          from ysgl_compile_reqsub
         where budget_year = 2012
           and orgid = 138
           and tempid = 1203) b,
       ysgl_excelbasic a,
       (select cellid, max(flag) flag
          from ysgl_tempprivilege
         where roleid in
               (select roleid from eosoperatorrole where operatorid = 138)
           and tempid = 1203
         group by cellid) c
 where a.cellid = b.cellid(+)
   and a.cellid = c.cellid(+)
   and a.tempid = 1203

看执行计划,正常,系统表的分析时间也昨天夜里,最新的,查询1000到1010记录,没反应,终止进程。查看是否有异常数据,里面嵌套着自定义的函数,函数通过读取、计算获得新的数据,展现在结果中。屏蔽掉函数部分,立刻有结果。看来问题就出在函数里面。

函数本身很简单,经过系列的条件判定,执行个sql读取一个值,貌似没问题,仔细分析,里面有个条件比较,列本身是varchar,传入条件是number,比较结果可能有错啊。汗!这长时间都没发现,也没出现错误数据! 万幸。不对啊,即使数据是错误的,也不应该没响应。突然想到,里面执行的sql也有这个问题,列是varchar,参数是number,这时候,oracle会做强制类型转换以匹配执行,索引失效啊!!!悲催的,2000万的表,如果索引失效,会是个啥现象。这个语句在一个时间内,会被成百上千的执行,因为里面定义的都是公式,类似:

(YS(752834,138,0)*YS(768618,138,0)+YS(752751,138,0)*YS(768186,138,0)+YS(752756,138,0)*YS(768809,138,0)+YS(752761,138,0)*YS(769508,138,0)+YS(752766,138,0)*YS(768849,138,0)+YS(752771,138,0)*YS(768100,138,0)+YS(752777,138,0)*YS(764941,138,0)+YS(752782,138,0)*YS(767913,138,0)+YS(752787,138,0)*YS(768536,138,0)+YS(752792,138,0)*YS(764968,138,0)+YS(752797,138,0)*YS(764921,138,0)+YS(752803,138,0)*YS(768549,138,0))/YS(768660,138,0)

每一个YS都是执行一次上面那个悲催的sql,每一列里都定义了上面的公式,每一个表里有两三千行,如何想象,什么样的机器都能搞瘫。

赶紧修改这个函数,把sql里面的比较条件端加上to_char,(因为涉及到函数的外部调用,所以,不能妄自修改参数传入类型),重新编译函数。

刚才那个10分钟的语句马上就执行完毕,继续观察数据库负载,CPU 和DISK负载一段时间后下降,以后虽然有点时间的上升,但很快下来,正常现象。

到这里,此次痛苦的工作结束,总结性的一句话,粗心大意害死人。做技术,严谨是第一位的。