在PL / SQL中的FOR LOOP中处理大量记录

时间:2017-03-13 13:21:15

标签: oracle plsql oracle11g

我有一个Oracle(11g)数据库,其中包含一个包含大约2亿条记录的表。我必须修改表中每行的两列。什么是最有效的解决方案?

我尝试使用与以下类似的代码,但过了一段时间后执行因ORA-04030 - Out of process memory而崩溃。

BEGIN
    FOR i IN (SELECT * FROM FOO WHERE BAR > 2000)
    LOOP
        -- Do the processing and update row
    END LOOP;
END;

我无法更改任何操作系统级参数。我必须使用代码来解决这个问题。

2 个答案:

答案 0 :(得分:2)

由于我不知道确切的色谱柱修改,我只会做些什么;假设我需要将名称更改为小写但是首字母大写,并且我必须根据工作提高工资。 这是最有效的方式。

我们假设我有一个200M行的MYEMP表。

create table temp_emp
as select * from myemp
where 1=2;

alter session enable parallel dml

insert /*+ APPEND */ into temp_emp
select 
  EMPNO  
, initcap(ENAME)  
, JOB    
, MGR    
, HIREDATE
, case when job = 'MANAGER' then SAL  * 1.1 else SAL * 1.05 end  
, COMM   
, DEPTNO 
from myemp
;

drop table myemp
;
  如果你需要“安全”,你可以重命名而不是丢弃MYEMP   仔细检查

rename temp_emp to myemp;

快速测试,有1400万行,使用串行执行需要16秒。通过使用数据库并行性,可以进一步减少运行时间。

答案 1 :(得分:1)

一种方法是将bulk collectlimit一起使用。只有有限的行(由limit子句定义)被提取到内存中,您可以循环执行所需的处理。

declare
    cursor cur_foo is
        select * from foo where bar > 2000;
    type tab is table of foo%rowtype;
    v_tab tab;
BEGIN
    open cur_foo;
    loop
        fetch cur_foo bulk collect into v_tab limit 100;
        exit when v_tab.count = 0;

        for idx in 1..v_tab.count loop
            -- do something with v_tab(idx)
        end loop;

    end loop;
    close cur_foo;
END;

您还可以使用FORALL进行批量插入,更新或删除操作。

在Oracle网站上查看有关这些功能的文章

和AskTOM上的这个问题: