Sql 使用脚本更新900万条记录时出现性能问题
我们一直在运行下面的脚本来更新运行11G oracle DB 11.2.0.3的表中的一些列,完成这项工作大约需要61个小时,这令人惊讶,因为我们正在使用批量收集和Forall进行实际更新。我们还启用了并行dml。我们也在尝试基于rowid进行更新,而不是使用索引的列,因为我们认为这样会更快。任何加快这一进程的建议都是非常好的。下面是脚本Sql 使用脚本更新900万条记录时出现性能问题,sql,plsql,oracle11g,Sql,Plsql,Oracle11g,我们一直在运行下面的脚本来更新运行11G oracle DB 11.2.0.3的表中的一些列,完成这项工作大约需要61个小时,这令人惊讶,因为我们正在使用批量收集和Forall进行实际更新。我们还启用了并行dml。我们也在尝试基于rowid进行更新,而不是使用索引的列,因为我们认为这样会更快。任何加快这一进程的建议都是非常好的。下面是脚本 ALTER session enable parallel dml; DECLARE i NUMBER; j number :=0 ; TYPE tab_ty
ALTER session enable parallel dml;
DECLARE
i NUMBER;
j number :=0 ;
TYPE tab_type IS TABLE OF rowid index by binary_integer;
tab_id tab_type;
CURSOR c1 IS
SELECT /*+ parallel(na,DEFAULT) */
rowid
from sample_table na
FOR UPDATE SKIP LOCKED;
BEGIN
OPEN c1;
LOOP
FETCH c1 BULK COLLECT INTO tab_id LIMIT 10000;
EXIT WHEN tab_id.COUNT = 0;
FORALL i IN 1..tab_id.COUNT
update sample_table
set col1 = 'XXX'
, col2 = 'XXX'
, col3 = 'XXX'
, col4 = 'XXX'
, col5= 'XXX'
, col6 = 'XXX'
WHERE rowid = tab_id(i);
j := j+1;
if mod(j, 1000) = 0 THEN -- Commit every 1000 records
COMMIT;
end if;
END LOOP;
CLOSE c1;
END;
/
我不能完全肯定这会对你的跑步时间产生影响,但我不能伤害它。此外,您的代码还指出了一些误解 首先,该语句不创建循环。它运行 单个合并1次,处理整个集合。 这也意味着您的提交间隔不是您指示的1000,而是 1米。 语句中的索引变量i是该变量的局部变量 语句,并且只能在forall的范围内访问 陈述因此,声明的变量i不是中使用的变量 因此,不需要forall和forall。没有错误,因为 范围界定规则。 由于退出循环后没有提交,最后一组将 除非行数是的精确倍数,否则不能提交 提交间隔。在具有1M行提交间隔的情况下,如果您有8999999行,则只会提交8M。 考虑到所有这些,您可以尝试:
declare
type tab_type is table of rowid;
tab_id tab_type;
k_buffer_limit constant pls_integer := 10000;
cursor c1 is
select /*+ parallel(na,DEFAULT) */
rowid
from sample_table na
for update skip locked;
begin
open c1;
loop
fetch c1 bulk collect into tab_id limit 10000
forall i in 1..tab_id.count
update sample_table
set col1 = 'XXX'
, col2 = 'XXX'
, col3 = 'XXX'
, col4 = 'XXX'
, col5= 'XXX'
, col6 = 'XXX'
where rowid = tab_id(i);
commit;
exit when tab_id.count < k_buffer_limit;
end loop;
close c1;
end;
批量收集/Forall处理是上下文切换之间的折衷
和内存使用情况。虽然减少上下文切换是一件好事,但是
可能会被内存需求所克服。您的流程可能是
进入等待以获得足够的内存。您可以通过以下方式获得更好的性能。
非常感谢你的建议。我认为在关闭光标后必须移动提交,因为它可能会导致提取顺序错误。提交不会进行另一次提取。它可以在close cursor之前或之后运行,并且对任何一种方式都没有影响。提交对游标既不了解也不影响,因为它们解决了v9前后提交中的游标不稳定性问题?还是v10?在那里的某个地方。谢谢你澄清这一点。