2012-11-30 67 views
0

我必須從運行時定義的表中獲取數據並獲取基於運行時定義的列的數據,現在我使用帶有ref cursor的動態sql作爲下面。有沒有更有效的方法來提高性能?如何提高在Oracle中動態sql的查詢性能

PROCEDURE check_error(p_table_name IN VARCHAR2 
    ,p_keyword IN VARCHAR2 
    ,p_column_name IN VARCHAR2 
    ,p_min_num IN NUMBER 
    ,p_time_range IN NUMBER 
    ,p_file_desc IN VARCHAR2 
    ) 
IS 
    type t_crs is ref cursor; 
    v_cur t_crs; 

    v_file_name VARCHAR2(100); 
    v_date_started DATE; 
    v_date_completed DATE; 
    v_counter NUMBER := 0; 
    v_sql VARCHAR2(500); 
    v_num NUMBER :=0; 
BEGIN 
    v_sql := 'SELECT '||p_column_name||', DATE_STARTED,DATE_COMPLETED FROM '||p_table_name 
      || ' WHERE '||p_column_name||' LIKE '''||p_keyword||'%'' AND DATE_STARTED > :TIME_LIMIT ORDER BY '||p_column_name; 

    OPEN v_cur FOR v_sql USING (sysdate - (p_time_range/1440)); 
    LOOP 
     FETCH v_cur INTO v_file_name,v_date_started,v_date_completed; 
     EXIT WHEN v_cur%NOTFOUND; 
     IF v_date_started IS NOT NULL AND v_date_completed IS NULL 
      AND (sysdate - v_date_started)*1440 > p_time_range THEN 
       insert_record(co_alert_stuck,v_file_name,p_table_name,0,p_file_desc,p_time_range);    
     END IF;   
    END LOOP; 
END; 

順便說一句,這會使它更好嗎?

v_sql := 'SELECT :COLUMN_NAME1, DATE_STARTED,DATE_COMPLETED FROM :TABLE WHERE :COLUMN_NAME2 LIKE :KEYWORD AND DATE_STARTED > :TIME_LIMIT ORDER BY :COLUMN_NAME3'; 

OPEN v_cur FOR v_sql USING p_column_name,p_table_name,p_column_name,p_keyword||'%',(sysdate - (p_time_range/1440)),p_column_name; 

回答

0

首先,我不確定我是否理解代碼正在做什麼。在您發佈的代碼中(您可能已減少以簡化操作),IF語句將檢查v_date_started IS NOT NULL是否爲冗餘,因爲DATE_STARTED上有WHERE子句。它檢查(sysdate - v_date_started)*1440 > p_time_range這是DATE_STARTED列中的WHERE子句的冗餘重複。它會檢查v_date_completed IS NULL作爲另一個WHERE子句在您創建的動態SQL語句中是否更有效。在一個地方完成所有的檢查是有意義的,並且最有效的地方是在SQL語句中。

其次,此查詢應該返回多少行,以及時間在哪裏?如果遊標可能返回許多行(對於許多定義),則從光標執行BULK COLLECT到集合並修改insert_record過程以接受和處理集合,您會獲得一定效率。如果時間都用在執行SQL語句上,並且查詢本身只返回少量行,那麼PL/SQL批量操作可能不會使事情變得更有效。如果瓶頸正在執行SQL語句,則需要希望在傳入的任何表上存在適當的索引。如果瓶頸是insert_record過程,那麼我們需要知道該過程正在做什麼評論。第三,如果insert_record過程(至少主要)只是將您獲取的數據插入到不同的表中,那麼擺脫所有循環並僅生成動態INSERT語句會更有效。第四,關於你的編輯,你不能使用表名或列名的綁定變量,所以你提出的語法是無效的。它不會更有效,因爲它會產生一堆語法錯誤。

+0

謝謝兄弟,我刪除了「v_date_started IS NOT NULL」這是一個很好的建議,我有另一部分代碼來檢查循環後的結果數量(使用v_cur%ROWCOUNT,沒有放在這裏),所以我不能把「v_date_completed IS NULL」放在where子句中。 行數通常在兩千。 insert_record只是將數據插入到全局臨時表中以生成報告。 – Frank