我有一个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;
我无法更改任何操作系统级参数。我必须使用代码来解决这个问题。
答案 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 collect
与limit
一起使用。只有有限的行(由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上的这个问题: