删除需要花费大量时间
Delete is taking considerable amount of time
我写了一个 plsql 块来删除一堆 table 的一些记录。
所以为了识别要删除的记录,我在该查询的顶部创建了一个游标。
declare
type t_guid_invoice is ref cursor;
c_invoice t_guid_invoice;
begin
open c_invoice for
select * from a,b where a.col=b.col ;--(quite a complex join,renders 200k records)
loop fetch c_invoice into col1,col2,col3;
exit when c_invoice%NOTFOUND;
begin
DELETE
FROM tab2
WHERE cola= col1;
if SQL%rowcount > 0 then
dbms_output.put_line ( 'INFO: tab2 for ' || col1|| '/' || col2|| ' removed.');
else
dbms_output.put_line ( 'WARN: No tab2 for ' || col1|| '/' || col2|| ' found!');
end if;
eXception
when others then
dbms_output.put_line ( 'ERR: Problems while deleting tab2 for ' || col1|| '/' || col2 );
dbms_output.put_line ( SQLERRM );
end;
....
end loop;
这样继续循环大约26tables,有一些tables有6000万条记录那么大。
删除基于每个 table 中的主键。在删除过程之前禁用所有触发器。
如果我尝试删除 10k 条记录,它会循环 10k 次,在每个 table 中删除多行,但它需要长达 30 分钟的时间。每个块之后没有提交,因为我也必须迎合模拟模式。
有什么建议可以加快这个过程吗?谢谢!
当然,如果你循环 10k 次,所有这些 DBMS_OUTPUT.PUT_LINE
调用都会减慢速度(即使你没有做任何“聪明”的事情)(我想知道缓冲区是否足够大)。如果您想记录发生的事情,请创建一个日志 table 和一个将插入该信息(并提交)的自治事务过程。
除此之外,table 的索引是否正确?例如。那将是 tab2
table 中的 cola
列(在您发布的代码中)。您是否收集了有关 table 和索引的统计信息?如果您对整个架构执行此操作可能不会造成伤害。
你检查解释计划了吗?
你知道什么最花时间吗?是引用游标查询(所以要优化),还是自己删除?
你不能完全避免循环吗?逐行处理很慢。例如,不使用 ref 游标,而是从中创建一个 table,对其进行索引,并将其用作
create table c_invoice as
select * from a join b on a.col = b.col;
create index i1inv_col1 on c_invoice (col1);
delete from tab2 t
where exists (select null
from c_invoice c
where c.col1 = t.cola
);
您通常从不 想要从循环中的 table 中删除大量行。
您想使用一个具有适当 WHERE
条件的 DELETE
语句。
此外,在处理大量行时,您通常 不想使用索引。
因此您的第一步将检查不会被删除的行(您的warnings
)
您通过以下查询获得 密钥,您可以记录它们
select a.col from a,b where a.col=b.col
minus
select cola from tab2;
在第二步你delete
所有行都用一个语句。
delete
from tab2
where cola in (select a.col from a,b where a.col=b.col);
在问题检查 中,您期望 TABLE ACCESS FULL
(INDEX FAST FULL SCAN
也很好)与 HASH JOIN
.
相结合的所有来源
我写了一个 plsql 块来删除一堆 table 的一些记录。 所以为了识别要删除的记录,我在该查询的顶部创建了一个游标。
declare
type t_guid_invoice is ref cursor;
c_invoice t_guid_invoice;
begin
open c_invoice for
select * from a,b where a.col=b.col ;--(quite a complex join,renders 200k records)
loop fetch c_invoice into col1,col2,col3;
exit when c_invoice%NOTFOUND;
begin
DELETE
FROM tab2
WHERE cola= col1;
if SQL%rowcount > 0 then
dbms_output.put_line ( 'INFO: tab2 for ' || col1|| '/' || col2|| ' removed.');
else
dbms_output.put_line ( 'WARN: No tab2 for ' || col1|| '/' || col2|| ' found!');
end if;
eXception
when others then
dbms_output.put_line ( 'ERR: Problems while deleting tab2 for ' || col1|| '/' || col2 );
dbms_output.put_line ( SQLERRM );
end;
....
end loop;
这样继续循环大约26tables,有一些tables有6000万条记录那么大。 删除基于每个 table 中的主键。在删除过程之前禁用所有触发器。 如果我尝试删除 10k 条记录,它会循环 10k 次,在每个 table 中删除多行,但它需要长达 30 分钟的时间。每个块之后没有提交,因为我也必须迎合模拟模式。 有什么建议可以加快这个过程吗?谢谢!
当然,如果你循环 10k 次,所有这些 DBMS_OUTPUT.PUT_LINE
调用都会减慢速度(即使你没有做任何“聪明”的事情)(我想知道缓冲区是否足够大)。如果您想记录发生的事情,请创建一个日志 table 和一个将插入该信息(并提交)的自治事务过程。
除此之外,table 的索引是否正确?例如。那将是 tab2
table 中的 cola
列(在您发布的代码中)。您是否收集了有关 table 和索引的统计信息?如果您对整个架构执行此操作可能不会造成伤害。
你检查解释计划了吗?
你知道什么最花时间吗?是引用游标查询(所以要优化),还是自己删除?
你不能完全避免循环吗?逐行处理很慢。例如,不使用 ref 游标,而是从中创建一个 table,对其进行索引,并将其用作
create table c_invoice as
select * from a join b on a.col = b.col;
create index i1inv_col1 on c_invoice (col1);
delete from tab2 t
where exists (select null
from c_invoice c
where c.col1 = t.cola
);
您通常从不 想要从循环中的 table 中删除大量行。
您想使用一个具有适当 WHERE
条件的 DELETE
语句。
此外,在处理大量行时,您通常 不想使用索引。
因此您的第一步将检查不会被删除的行(您的warnings
)
您通过以下查询获得 密钥,您可以记录它们
select a.col from a,b where a.col=b.col
minus
select cola from tab2;
在第二步你delete
所有行都用一个语句。
delete
from tab2
where cola in (select a.col from a,b where a.col=b.col);
在问题检查 TABLE ACCESS FULL
(INDEX FAST FULL SCAN
也很好)与 HASH JOIN
.