程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> Oracle數據庫 >> Oracle教程 >> ORACLE應用調優:請避免SQL做大量循環邏輯處理,oracle調優

ORACLE應用調優:請避免SQL做大量循環邏輯處理,oracle調優

編輯:Oracle教程

ORACLE應用調優:請避免SQL做大量循環邏輯處理,oracle調優


    前陣子遇到一個案例:一個同事說以前一個運行很正常的包,突然間比以前慢了很多,執行時間非常長,晚上的作業調用這個包跑了幾個小時也沒有跑出數據。於是我在跟蹤、優化過程中定位到包中一個存儲過程的一段SQL,我將原SQL簡化了一下(對應的表名、函數全都隨機取名替換掉),大體如下所示,在一個游標中,循環更新表TMP_JO_ORDERS, 其中需要通過函數獲取一些值,這些值用來更新目標表的字段值

 

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分鐘就運行出來了。

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;

 

     其實這只是一個特殊的案例,我只是將其當做一個引子,引入我想闡述的觀點:我們知道SQL是結構化查詢語言,擅長於結構化查詢,而不擅長於邏輯處理(WHIE、IF..ELSE),但是有時候,很多人喜歡用SQL來處理業務邏輯,當然也不是說不能在存儲過程、函數裡面做一些業務邏輯處理,只是發現不少人過度放大SQL的邏輯處理功能,將復雜的邏輯運算全部搬到包、存儲過程裡面處理,例如上面的循環運算,這樣做的一個糟糕結果就是性能問題,就好像一個擅長於短跑的人,你硬要他去參加長跑。那麼比賽結果肯定不會好到哪裡去。

 

    在開發中,我們要對業務邏輯做一些優化處理,避免復雜的邏輯運算,尤其避免循環次數非常大的業務邏輯處理,一方面我們要簡化業務邏輯,有些業務邏輯運算轉到程序中去處理,另外一方面我們可以用SQL很巧妙的實現很多邏輯復雜的需求,避免我們去做大量復雜的邏輯處理,而不要在復雜的業務下寫出更加復雜的SQL語句.例如上面的例子,我以前在一篇文章MS SQL 挑戰問題也述說了這樣一種觀念。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved