如何在Oracle中加速循环?

时间:2014-10-29 19:20:56

标签: sql oracle for-loop plsql

我正在使用Oracle版本> 10gR2中。 我有一张有2000万条记录的桌子。我想在将它们导出到文件之前处理所有记录,但是这样做的速度非常慢。

你有什么建议吗?以下是我的代码:

declare   
  l_temp_detail clob := null;    
  icount number:=0;

  cursor c_test is
    select /*+ PARALLEL(12) */ *
      from test_table t;

  TYPE t_test IS TABLE OF test_table%ROWTYPE INDEX BY PLS_INTEGER;
  l_test_items t_test;   

BEGIN
  l_temp_detail := '';  

  OPEN c_test;

  LOOP
    FETCH c_test 
      BULK COLLECT INTO l_test_items LIMIT 25000; 
    EXIT WHEN l_test_items.COUNT = 0;

    FOR i in l_test_items.first .. l_test_items.last      LOOP    
      icount := icount+1;     
      --doing business here
      l_temp_detail := ....
    END LOOP;      

    dbms_output.put_line(to_char(icount));   
  END LOOP;

  CLOSE c_test;    
END;

3 个答案:

答案 0 :(得分:0)

一些事情。仅使用您需要的test_table列。根据您的需要,您似乎只需要来自test_table的一些列和有限的记录集。你不会在一起连接2000万条记录。

此外,由于表格很大,您可能需要检查是否存在任何分区和索引。使用特定partition和右index将增强查询执行时间。

答案 1 :(得分:0)

Parallel table functions启用并行查询和并行程序处理。

示例表和数据。

drop table test_table;
create table test_table(a number);
insert into test_table select level from dual connect by level <= 1000000;
commit;

退货类型(即使您不关心结果,也需要退货)

create or replace type number_nt is table of number;

并行管道列表功能

--The syntax is very picky if you want to enable parallelism.
create or replace function f(p_cursor in sys_refcursor) return number_nt
    pipelined parallel_enable(partition p_cursor by any) is

    l_temp_detail clob := null;    
    icount number:=0;

    type t_test is table of test_table%rowtype index by pls_integer;
    l_test_items t_test;   
begin
    LOOP
        FETCH p_cursor 
            BULK COLLECT INTO l_test_items LIMIT 25000; 
        EXIT WHEN l_test_items.COUNT = 0;

        FOR i in l_test_items.first .. l_test_items.last LOOP    
            icount := icount+1;     
            --doing business here
            --l_temp_detail := ....
        END LOOP;      

        dbms_output.put_line(to_char(icount));   
    END LOOP;
    CLOSE p_cursor;    

    pipe row (icount);
end;
/

查询和结果

--You may want to SUM() to get a total count.
--These aren't the results you care about, but they help show the distribution.
select column_value
from table(f(cursor(select /*+ parallel(12) */ * from test_table)));

COLUMN_VALUE
------------
124080
116160
65340
58080
79860
65340
60060
79860
59400
46960
116160
128700

答案 2 :(得分:0)

我实际上没有在10g上测试过这个,但是在Oracle9上处理plsql表中的大量记录比处理单个值表的效率要低10倍。

所以 - 如果您将代码从“记录表”重构为“表记录”,您可能会看到显着的改进。你实际上并不需要将各个表捆绑在一个记录中 - 为了清楚起见,我只是喜欢它。

E.g。

declare
  type tName    is table of mytable.name%type index by pls_integer;
  type tAddress is table of mytable.address%type index by pls_integer;
  type tPerson  is record (
                     name     tName;
                     address  tAddress;
                     );
  person tPerson;
begin
  open somecursor;
  loop
    fetch somecursor bulk collect into person.name, person.address limit 25000;
    --
    -- processeing
    --
    exit when ...
  end loop;
  close somecursor;
end;

我不能保证这肯定会解决您的问题 - 这取决于您在“处理”中对数据的实际操作 - 例如,在plsql中花费了多少时间以及在SQL中花了多少时间做dml。