我必须从运行时定义的表中获取数据并根据运行时定义的列获取数据,我现在使用带有ref cursor的动态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 :(得分:0)
首先,我不确定我是否理解代码正在做什么。在您发布的代码中(您可能已将其缩减以简化操作),IF
语句会检查v_date_started IS NOT NULL
是否为冗余,因为WHERE
上有DATE_STARTED
条款。它会检查(sysdate - v_date_started)*1440 > p_time_range
是否只是WHERE
列上DATE_STARTED
子句的冗余重复。它会检查v_date_completed IS NULL
是否更有效,作为您构建的动态SQL语句中的附加WHERE
子句。在一个地方完成所有检查是有意义的,最有效的地方就是在SQL语句中。
其次,此查询应返回多少行以及花费的时间在哪里?如果游标可能返回许多行(对于许多行的定义),从游标到集合中执行BULK COLLECT
并修改insert_record
过程以接受和处理,您将获得一些效率一个集合。如果所有时间都花在执行SQL语句上,并且查询本身只返回少量行,则PL / SQL批量操作可能不会使事情明显更高效。如果瓶颈正在执行SQL语句,那么您需要希望在传入的任何表上都存在适当的索引。如果瓶颈是insert_record
过程,我们需要知道该过程在做什么评论。
第三,如果insert_record
过程(至少主要是)只是将您获取的数据插入到不同的表中,那么摆脱所有循环并生成动态{{ 1}}陈述。
第四,关于编辑,您不能对表名或列名使用绑定变量,因此您提出的语法无效。它不会更有效,因为它会产生一堆语法错误。