2012-11-30 66 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