ORACLE应用调优:请避免SQL作大量循环逻辑处理

    前阵子遇到一个案例:一个同事说之前一个运行很正常的包,忽然间比之前慢了不少,执行时间很是长,晚上的做业调用这个包跑了几个小时也没有跑出数据。因而我在跟踪、优化过程当中定位到包中一个存储过程的一段SQL,我将原SQL简化了一下(对应的表名、函数全都随机取名替换掉),大致以下所示,在一个游标中,循环更新表TMP_JO_ORDERS, 其中须要经过函数获取一些值,这些值用来更新目标表的字段值html

 

FOR CUR_JO IN (SELECT JOB_ORDER_NO FROM TMP_JO_ORDERS WHERE SEW_START >=SYSDATE ) LOOP函数

        SELECT MAIN_ITC.GET_MUST_INFO(CUR_JO.JOB_ORDER_NO,'SEWING','BUTTON')   INTO MY_M_BUTTON FROM DUAL;
        SELECT MAIN_ITC.GET_MUST_INFO(CUR_JO.JOB_ORDER_NO,'SEWING','LABEL')    INTO MY_M_LABEL  FROM DUAL;
        SELECT MAIN_ITC.GET_MUST_INFO(CUR_JO.JOB_ORDER_NO,'SEWING','TAPE')     INTO MY_M_TAPE   FROM DUAL;
        SELECT MAIN_ITC.GET_MUST_INFO(CUR_JO.JOB_ORDER_NO,'SEWING','ZIPPER')   INTO MY_M_ZIPPER FROM DUAL;
        SELECT MAIN_ITC.GET_MUST_INFO(CUR_JO.JOB_ORDER_NO,'SEWING','OTHERS')   INTO MY_M_OTHERS FROM DUAL;
        SELECT MAIN_ITC.GET_MUST_INFO(CUR_JO.JOB_ORDER_NO,'THREAD','ALL')      INTO MY_M_THREAD FROM DUAL;
        SELECT MAIN_ITC.GET_MUST_INFO(CUR_JO.JOB_ORDER_NO,'INTERLINING','ALL') INTO MY_M_INTERLINING FROM DUAL;
        SELECT MAIN_ITC.GET_MUST_INFO(CUR_JO.JOB_ORDER_NO,'PACKING','ALL')     INTO MY_M_PACKING FROM DUAL;
       
        UPDATE TMP_JO_ORDERS A
        SET M_BUTTON=MY_M_BUTTON
             ,M_LABEL=MY_M_LABEL
             ,M_TAPE=MY_M_TAPE
             ,M_ZIPPER=MY_M_ZIPPER
             ,M_OTHERS=MY_M_OTHERS
             ,M_THREAD=MY_M_THREAD
             ,M_INTERLINING=MY_M_INTERLINING
             ,M_PACKING=MY_M_PACKING
        WHERE JOB_ORDER_NO=CUR_JO.JOB_ORDER_NO;
END LOOP;
性能

 

其实之前运行正常,忽然出现性能问题,是由于SELECT JOB_ORDER_NO FROM TMP_JO_ORDERS WHERE SEW_START >=SYSDATE的数据量因为业务量忽然增长了不少,因此游标的循环次数从之前几十次忽然飚增到8千屡次。 测试

假设游标里面的SQL执行时间须要2秒,之前只循环了30次,那么运算该SQL须要2*30=60秒,若是循环次数忽然飚增到8000次,2*8000=16000秒,这就是几个小时的时间。你能够想象一下,这个性能会忽然降低到一种没法忍受的程度!优化

那么怎么优化呢? 固然是减小循环次数。仔细观察了这段SQL,弄明白写这个SQL的老兄的业务逻辑后,上面的循环处理彻底能够用下面一个SQL语句替换,彻底没有必要一条记录一条记录更新。当时修改后测试,发现修改后的SQL,不到1分钟就运行出来了。code

UPDATE TMP_JO_ORDERS A
        SET M_BUTTON     =MAIN_INTERFACE.GET_MUST_INFO(JOB_ORDER_NO,'SEWING','BUTTON')
             ,M_LABEL      =MAIN_INTERFACE.GET_MUST_INFO(JOB_ORDER_NO,'SEWING','LABEL')
             ,M_TAPE       =MAIN_INTERFACE.GET_MUST_INFO(JOB_ORDER_NO,'SEWING','TAPE')
             ,M_ZIPPER     =MAIN_INTERFACE.GET_MUST_INFO(JOB_ORDER_NO,'SEWING','ZIPPER')
             ,M_OTHERS     =MAIN_INTERFACE.GET_MUST_INFO(JOB_ORDER_NO,'SEWING','OTHERS')
             ,M_THREAD     =MAIN_INTERFACE.GET_MUST_INFO(JOB_ORDER_NO,'THREAD','ALL')
             ,M_INTERLINING=MAIN_INTERFACE.GET_MUST_INFO(JOB_ORDER_NO,'INTERLINING','ALL')
             ,M_PACKING    =MAIN_INTERFACE.GET_MUST_INFO(JOB_ORDER_NO,'PACKING','ALL')
    WHERE SEW_START >=SYSDATE;
htm

 

     其实这只是一个特殊的案例,我只是将其当作一个引子,引入我想阐述的观点:咱们知道SQL是结构化查询语言,擅长于结构化查询,而不擅长于逻辑处理(WHIE、IF..ELSE),可是有时候,不少人喜欢用SQL来处理业务逻辑,固然也不是说不能在存储过程、函数里面作一些业务逻辑处理,只是发现很多人过分放大SQL的逻辑处理功能,将复杂的逻辑运算所有搬到包、存储过程里面处理,例如上面的循环运算,这样作的一个糟糕结果就是性能问题,就好像一个擅长于短跑的人,你硬要他去参加长跑。那么比赛结果确定不会好到哪里去。blog

 

    在开发中,咱们要对业务逻辑作一些优化处理,避免复杂的逻辑运算,尤为避免循环次数很是大的业务逻辑处理,一方面咱们要简化业务逻辑,有些业务逻辑运算转到程序中去处理,另一方面咱们能够用SQL很巧妙的实现不少逻辑复杂的需求,避免咱们去作大量复杂的逻辑处理,而不要在复杂的业务下写出更加复杂的SQL语句.例如上面的例子,我之前在一篇文章MS SQL 挑战问题也述说了这样一种观念。开发

相关文章
相关标签/搜索