I have to fetch data from a running-time-defined table and get data based on a running-time-defined column, I’m now using dynamic sql with ref cursor as below. Is there any more efficient ways to improve the performance ?
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;
BTW, will this make it better ?
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;
First, I’m not sure that I understand what the code is doing. In the code you posted (which you may have cut down to simplify things), the
IFstatement checks whetherv_date_started IS NOT NULLwhich is redundant since there is aWHEREclause onDATE_STARTED. It checks whether(sysdate - v_date_started)*1440 > p_time_rangewhich is just a redundant repetition of theWHEREclause on theDATE_STARTEDcolumn. And it checks whetherv_date_completed IS NULLwhich would be more efficient as an additionalWHEREclause in the dynamic SQL statement that you built. It would make sense to do all of your checks in exactly one place and the most efficient place to do them would be in the SQL statement.Second, how many rows should this query return and where is the time being spent? If the cursor potentially returns many rows (for some definition of many), you’ll get a bit of efficiency from doing a
BULK COLLECTfrom the cursor into a collection and modifying theinsert_recordprocedure to accept and process a collection. If the time is all spent executing the SQL statement and the query itself returns just a handful of rows, PL/SQL bulk operations would probably not make things appreciably more efficient. If the bottleneck is executing the SQL statement, you’d need to hope that an appropriate index existed on whatever table was passed in. If the bottleneck is theinsert_recordprocedure, we’d need to know what that procedure is doing to comment.Third, if the
insert_recordprocedure is (at least primarily) just inserting the data that you fetched into a different table, it would be more efficient to get rid of all the looping and just generate a dynamicINSERTstatement.Fourth, with respect to your edit, you cannot use bind variables for table names or column names so the syntax you’re proposing is invalid. It won’t be more efficient because it will generate a bunch of syntax errors.